https://engineering.linecorp.com/ko/blog/the-7-ways-of-counting-characters
글자수를 세는 7가지 방법
안녕하세요. 라인플러스 개발실에서 일하고 있는 박상진입니다. 이 블로그에서는 글자 수를 세는 방법에 대해서 얘기해보고자 합니다. 라인 서비스에서는 프로필이름, 그룹이름, 상태메시지 등
engineering.linecorp.com
라인의 기술 블로그를 보다가 문자를 표현하는 방법에 대해 궁금해져 정리 해봅니다.
본문에서 나오는 Code Units와 Code Point가 처음에는 이해가 좀 안됐었는데요,
Code Units는 text 인코딩에 있어서 처리를 위한, 한단위를 표현할 수 있는 최소한의 비트 조합이라고 하는데
이해가 잘 되지 않아, 구글에 검색을 해보았습니다.
https://developer.mozilla.org/ko/docs/Glossary/Code_unit
코드 단위 (Code unit) - MDN Web Docs 용어 사전: 웹 용어 정의 | MDN
코드 단위는 문자 인코딩 시스템(예, UTF-8 또는 UTF-16)에서 사용되는 기본 구성 요소입니다. 문자 인코딩 시스템은 하나 이상의 코드 단위를 사용하여 유니코드 코드 포인트를 인코딩합니다.
developer.mozilla.org
모질라 재단에 친절하게 나와있는데, 문자 인코딩 시스템은 하나 이상의 코드 유닛을 사용하여 유니 코드 코드 포인트를 인코딩한다고 되어있습니다. 그렇다면 우리가 보는 텍스트는 코드 포인트로 이루어져 있는건가? 싶습니다.
코드 포인트는 코드 단위를 사용하여 텍스트를 인코딩 한다고 했는데 예를 들어 문자 한 개가 코드 포인트라면, 코드 포인트 한 개가 코드 단위는 아니라는 뜻 입니다. 예제를 보면
const myString = "\u006E\u0303";
console.log(myString); // ñ
console.log(myString.length); // 2
\u006E, \u0303이라는 코드 포인트 두개가 이루어져 코드 유닛 한개를 만들었습니다.
자바에서도 String 객체에 codePointAt() 메서드가 있어, 유니코드 포인트를 검색할 수도 있습니다.
"hello".codePointAt(0);
이렇게 보면 문자열 == 코드 포인트 > 인코딩(코드 유닛) 라고 해석할 수 있습니다.
그럼 본문에서 나오는 Grapheme Clusters는 뭘까? 싶은데..
단일 유니코드 코드 포인트는 문자의 길이를 표현하기가 힘듭니다.
String a = "ㅁ";
System.out.println(a.getBytes(StandardCharsets.UTF_8).length);
System.out.println(a.getBytes(StandardCharsets.UTF_16).length);
// 각각 출력은 1, 3, 4
이렇게 보면 length로 표현하면 되지않느냐?라고 하지만, 라인 블로그에 나와있듯 이모지의 경우는 표현이 안되는 경우가 있습니다. 블로그를 보고 띵 했던게 태국 문자는 생각해 본 적도 없는데 사실 처음 보는 입장에서는 해괴한 문자들의 길이를 세는데요. 왜 이모지가 2글자로 보일까요? 그건 바로 utf16으로 인코딩하면서, 위에서 말했던 코드 유닛이 한 개를 표현할 때 두 개의 코드 유닛이 필요할 수도 있기 때문입니다.
String a = "😄";
System.out.println(a.length());
System.out.println(a.getBytes(StandardCharsets.UTF_8).length);
System.out.println(a.getBytes(StandardCharsets.UTF_16).length);
// 각각 2, 4, 6
그래서 Grapheme 을 이용해 문자를 카운트 하는 방법도 있는 것 같습니다.
단순히 바이트 단위로 센다는 것은 알지만 저렇게 이모지의 경우까지는 생각을 못 했었던 것 같습니다.