{ }codelper
문자열 길이P0341

한글이 섞인 메시지의 남은 글자 수

문자 메시지 한 통에는 m글자까지 쓸 수 있다. 첫 줄에 m이, 둘째 줄에 쓴 메시지가 주어진다. 메시지는 한글, 영어 글자, 숫자, 문장 부호(.
, !
?), 빈칸으로 이루어진다. 글자 수는 눈에 보이는 글자를 하나씩 센 것이다. 한글 한 글자도, 영어 한 글자도, 빈칸 하나도 한 글자다. 예를 들어 "안녕 hi"는 5글자다. m에서 메시지의 글자 수를 뺀 값을 출력하라. 이 값이 양수이면 그만큼 더 쓸 수 있고, 0이면 딱 맞게 썼고, 음수이면 그만큼 넘쳤다는 뜻이다. 넘쳤을 때는 -3처럼 빼기 기호를 붙여 쓴다.

입력
1 ≤ m ≤ 1,000(쉼표 없이 숫자만 주어진다).
메시지는 1글자 이상 200글자 이하이고, 빈칸으로 시작하거나 끝나지 않는다.
한글은 '가'부터 '힣'까지의 완성된 글자만 나온다(ㄱ, ㅏ 같은 낱자나 그림 문자는 없다).
입력은 UTF-8로 주어진다
출력
m에서 메시지의 글자 수를 뺀 값을 한 줄에
예시 1 · stdin
10
안녕 hi
stdout
5
예시 2 · stdin
5
코델퍼 최고!!
stdout
-3
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

문자열의 길이는 Python len(s), JS·TS s.length, Java s.length(), C# s.Length, C strlen(s), C++ s.size(), 크레이콘 s.길이로 물어요.
그런데 세는 단위가 달라요.
Python은 글자(코드 포인트)를 세요.
JS·TS·Java·C#·크레이콘은 UTF-16 단위를 세는데, 한글 한 글자는 한 단위라서 이 문제에서는 글자 수와 같아요.
C와 C++은 바이트를 세요.
함정 하나: UTF-8에서 한글 한 글자는 3바이트예요.
그래서 strlen이나 size()를 그대로 쓰면 예시 1의 "안녕 hi"가 5가 아니라 9로 세어져 1이 나와요.
C·C++에서는 글자의 첫 바이트만 세면 돼요.
UTF-8에서 한 글자의 둘째 바이트부터는 모두 이진수 10으로 시작하므로, (c & 0xC0) != 0x80인 바이트의 수가 글자 수예요.
함정 둘: C의 strlen과 C++의 size()는 부호 없는 정수(size_t)를 돌려줘요.
C++에서 글자 수를 size_t에 세어 m - count를 찍으면 음수가 되지 못하고 아주 큰 수로 돌아서, 예시 2가 -3이 아니라 18446744073709551613으로 나와요.
int에 세거나 int로 바꾼 다음에 빼요.
함정 셋: 메시지에 빈칸이 있으니 줄을 통째로 읽어야 해요.
C++ cin >> msg는 첫 빈칸에서 멈춰서 예시 1이 8이 돼요(std::getline을 써요).
덧붙여, 이 문제에는 나오지 않는 그림 문자 😀 하나를 Python은 1로, JS·TS·Java·C#·크레이콘은 2로 세고, C·C++에서는 4바이트예요.

Pythonmain.py · 4 줄
m = int(input())msg = input()# len은 바이트가 아니라 글자(코드 포인트)를 센다: len("안녕") == 2print(m - len(msg))
JavaScriptmain.js · 5 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const m = Number(lines[0]);const msg = lines[1];// length는 UTF-16 단위의 수다. 한글 한 글자는 한 단위라 글자 수와 같다console.log(m - msg.length);
TypeScriptmain.ts · 6 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const m: number = Number(lines[0]);const msg: string = lines[1];// length는 UTF-16 단위의 수다. 한글 한 글자는 한 단위라 글자 수와 같다console.log(m - msg.length);
JavaMain.java · 13 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.nio.charset.StandardCharsets; public class Main {    public static void main(String[] args) throws Exception {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));        int m = Integer.parseInt(br.readLine().trim());        String msg = br.readLine();        // length()는 UTF-16 단위의 수다. 한글 한 글자는 한 단위라 글자 수와 같다        System.out.println(m - msg.length());    }}
C#Main.cs · 12 줄
using System; class Program{    static void Main()    {        int m = int.Parse(Console.ReadLine());        string msg = Console.ReadLine();        // Length는 UTF-16 단위의 수다. 한글 한 글자는 한 단위라 글자 수와 같다        Console.WriteLine(m - msg.Length);    }}
C++main.cpp · 18 줄
#include <iostream>#include <limits>#include <string> int main() {    int m;    std::cin >> m;    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');    std::string msg;    std::getline(std::cin, msg);    // size()는 바이트 수를 준다. UTF-8에서 글자의 첫 바이트만 세면 글자 수다    // (둘째 바이트부터는 모두 10xxxxxx 꼴이다)    int count = 0;   // size_t가 아니라 int: m - count가 음수가 될 수 있다    for (unsigned char c : msg) {        if ((c & 0xC0) != 0x80) count++;    }    std::cout << m - count << "\n";}
Cmain.c · 17 줄
#include <stdio.h>#include <stdlib.h> int main(void) {    char num[16], msg[700];   /* 한글 한 글자가 3바이트라 200글자면 600바이트까지 */    if (!fgets(num, sizeof num, stdin)) return 0;    if (!fgets(msg, sizeof msg, stdin)) return 0;    int m = atoi(num);    int count = 0;    /* strlen은 바이트 수를 준다. UTF-8에서 글자의 첫 바이트만 세면 글자 수다       (둘째 바이트부터는 모두 10xxxxxx 꼴이다) */    for (int i = 0; msg[i] != '\0' && msg[i] != '\n'; i++) {        if (((unsigned char)msg[i] & 0xC0) != 0x80) count++;    }    printf("%d\n", m - count);    return 0;}
Craykonmain.cray · 4 줄
m = 콘솔.줄읽기().수로변환();msg = 콘솔.줄읽기();// 길이는 글자 수다: "안녕".길이 == 2콘솔.쓰기(m - msg.길이);