{ }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()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

求字符串长度的写法:Python len(s),JS、TS s.length,Java s.length(),C# s.Length,C strlen(s),C++ s.size(),Craykon s.长度。
但它们数的单位不一样。
Python 数的是字符(码点)。
JS、TS、Java、C#、Craykon 数的是 UTF-16 单元,一个韩文字正好是一个单元,所以在本题里等于字符数。
C 和 C++ 数的是字节。
陷阱一:在 UTF-8 中一个韩文字占 3 个字节。
所以直接用 strlen 或 size(),例 1 的 "안녕 hi" 会被数成 9 而不是 5,结果输出 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#、Craykon 数成 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.长度);