IT story

C ++의 UTF-8에서 std :: string을 올바르게 사용하려면 어떻게해야합니까?

hot-time 2021. 1. 7. 19:59
반응형

C ++의 UTF-8에서 std :: string을 올바르게 사용하려면 어떻게해야합니까?


내 플랫폼은 Mac 및 C ++ 11 (또는 그 이상)입니다. 저는 C ++ 초보자이며 중국어와 영어를 처리하는 개인 프로젝트를 진행하고 있습니다. UTF-8은이 프로젝트의 기본 인코딩입니다.

나는 Stack Overflow에 대한 몇 가지 게시물을 읽었으며 그중 많은 사람들이 std::stringUTF-8을 다룰 때 사용 하고 UTF-8에 대한 현재가 wchar_t없으므로 피하는 것이 좋습니다 char8_t.

그러나 그들 중 누구도 제대로 같은 기능을 처리하는 방법에 대해 이야기하지 str[i], std::string::size(), std::string::find_first_of()또는 std::regexUTF-8에 직면 할 때 이러한 기능은 일반적으로 예기치 않은 결과를 반환한다.

계속 진행 std::string하거나로 전환해야 std::wstring합니까? 에 머물러야한다면 std::string위의 문제를 처리하는 가장 좋은 방법은 무엇입니까?


유니 코드 용어집

유니 코드는 방대하고 복잡한 주제입니다. 너무 깊이 들어가고 싶지는 않지만 빠른 용어집이 필요합니다.

  1. 코드 포인트 : 코드 포인트는 유니 코드의 기본 구성 요소이며, 코드 포인트는 의미에 매핑 된 정수일뿐입니다 . 정수 부분은 32 비트 (실제로는 24 비트)에 적합하며 그 의미는 문자, 분음 부호, 공백, 기호, 스마일리, 반쪽 플래그 등이 될 수 있습니다. 다음 부분은 오른쪽에서 왼쪽으로 읽습니다. "
  2. Grapheme Clusters : Grapheme Clusters는 의미 적으로 관련된 코드 포인트의 그룹입니다. 예를 들어 유니 코드의 플래그는 두 개의 코드 포인트를 연결하여 표시됩니다. 이 두 가지 각각은 따로 의미가 없지만 Grapheme Cluster에서 함께 연결되어 플래그를 나타냅니다. Grapheme Clusters는 일부 스크립트에서 문자를 분음 부호와 쌍을 이루는데도 사용됩니다.

이것이 유니 코드의 기본입니다. 대부분의 현대 언어의 경우 각 "문자"가 단일 코드 포인트에 매핑되기 때문에 코드 포인트와 Grapheme 클러스터 사이의 차이는 대체로 간과 될 수 있습니다 (일반적으로 사용되는 문자 + 분음 부호 조합에 대한 전용 악센트 형식이 있습니다). 그래도 스마일리, 깃발 등을 사용한다면 구별에주의를 기울여야 할 수도 있습니다.


UTF 입문서

그런 다음 일련의 유니 코드 코드 포인트를 인코딩해야합니다. 일반적인 인코딩은 UTF-8, UTF-16 및 UTF-32이며, 후자의 두 가지는 Little-Endian 및 Big-Endian 형식으로 존재하며 총 5 개의 공통 인코딩이 있습니다.

UTF-X에서 X는 코드 단위의 비트 크기이며 , 각 코드 포인트는 크기에 따라 하나 또는 여러 코드 단위로 표시됩니다.

  • UTF-8 : 1 ~ 4 코드 단위,
  • UTF-16 : 1 개 또는 2 개의 코드 단위,
  • UTF-32 : 1 코드 단위.

std::stringstd::wstring.

  1. std::wstring이식성에 관심이 있다면 사용하지 마십시오 ( wchar_tWindows에서는 16 비트 만 가능). 사용하는 std::u32string대신 (일명 std::basic_string<char32_t>).
  2. 메모리 내 표현 ( std::string또는 std::wstring)은 디스크상의 표현 (UTF-8, UTF-16 또는 UTF-32)과 무관하므로 경계 (읽기 및 쓰기)에서 변환해야 할 준비를하십시오.
  3. 32 비트 wchar_t는 코드 단위가 전체 코드 포인트를 나타내도록 보장하지만 여전히 완전한 Grapheme 클러스터를 나타내지는 않습니다.

문자열을 읽거나 작성하는 경우 std::string또는 std::wstring.

슬라이싱과 다이 싱을 시작할 때 문제가 시작되면 (1) 코드 포인트 경계 (UTF-8 또는 UTF-16) 및 (2) Grapheme 클러스터 경계에주의를 기울여야합니다. 전자는 쉽게 처리 할 수 ​​있으며 후자는 유니 코드 인식 라이브러리를 사용해야합니다.


따기 std::string또는 std::u32string?

성능이 문제라면 std::string메모리 사용량이 적기 때문에 더 나은 성능을 발휘할 수 있습니다 . 중국어를 많이 사용하면 거래가 달라질 수 있습니다. 항상 그렇듯이 프로필.

Grapheme Clusters가 문제가되지 않는다면 std::u32string일을 단순화하는 이점이 있습니다. 1 Code Unit- > 1 Code Point는 실수로 코드 포인트를 분리 할 수 ​​없음을 의미하며 모든 std::basic_string작업 기능을 즉시 사용할 수 있습니다.

당신이 소프트웨어 복용과 인터페이스하는 경우 std::string또는 char*/ char const*다음에 충실 std::string앞뒤로 변환을 방지하기 위해. 그렇지 않으면 고통이 될 것입니다.


UTF-8 std::string.

UTF-8은 실제로 std::string.

UTF-8 인코딩이 자체 동기화되고 ASCII와 역 호환되기 때문에 대부분의 작업은 기본적으로 작동합니다.

코드 포인트가 인코딩되는 방식으로 인해 코드 포인트를 찾는 것은 실수로 다른 코드 포인트의 중간과 일치 할 수 없습니다.

  • str.find('\n') 공장,
  • str.find("...")1 바이트 단위로 일치하는 작업 ,
  • str.find_first_of("\r\n")ASCII 문자를 검색하는 경우 작동 합니다 .

유사하게, regex대부분은 즉시 작동합니다. 일련의 문자 ( "haha")는 단순히 일련의 바이트 ( "哈")이므로 기본 검색 패턴이 즉시 작동합니다.

그러나 [:alphanum:]정규식 버전 및 구현에 따라 유니 코드 문자와 일치 할 수도 있고 일치하지 않을 수도 있으므로 문자 클래스 (예 :)에주의하십시오 .

마찬가지로 비 ASCII "문자"에 repeater를 적용하는 것에주의 "哈?"하십시오. 마지막 바이트 만 선택 사항으로 간주 할 수 있습니다. 다음과 같은 경우 괄호를 사용하여 반복되는 바이트 시퀀스를 명확하게 설명 "(哈)?"합니다..

1 The key concepts to look-up are normalization and collation; this affects all comparison operations. std::string will always compare (and thus sort) byte by byte, without regard for comparison rules specific to a language or a usage. If you need to handle full normalization/collation, you need a complete Unicode library, such as ICU.


Both std::string and std::wstring must use UTF encoding to represent Unicode. On macOS specifically, std::string is UTF-8 (8-bit code units), and std::wstring is UTF-32 (32-bit code units); note that the size of wchar_t is platform-dependent.

For both, size tracks the number of code units instead of the number of code points, or grapheme clusters. (A code point is one named Unicode entity, one or more of which form a grapheme cluster. Grapheme clusters are the visible characters that users interact with, like letters or emojis.)

Although I'm not familiar with the Unicode representation of Chinese, it's very possible that when you use UTF-32, the number of code units is often very close to the number of grapheme clusters. Obviously, however, this comes at the cost of using up to 4x more memory.

The most accurate solution would be to use a Unicode library, such as ICU, to calculate the Unicode properties that you are after.

Finally, UTF strings in human languages that don't use combining characters usually do pretty well with find/regex. I'm not sure about Chinese, but English is one of them.


std::string and friends are encoding-agnostic. The only difference between std::wstring and std::string are that std::wstring uses wchar_t as the individual element, not char. For most compilers the latter is 8-bit. The former is supposed to be large enough to hold any unicode character, but in practice on some systems it isn't (Microsoft's compiler, for example, uses a 16-bit type). You can't store UTF-8 in std::wstring; that's not what it's designed for. It's designed to be an equivalent of UTF-32 - a string where each element is a single Unicode codepoint.

If you want to index UTF-8 strings by Unicode codepoint or composed unicode glyph (or some other thing), count the length of a UTF-8 string in Unicode codepoints or some other unicode object, or find by Unicode codepoint, you're going to need to use something other than the standard library. ICU is one of the libraries in the field; there may be others.

Something that's probably worth noting is that if you're searching for ASCII characters, you can mostly treat a UTF-8 bytestream as if it were byte-by-byte. Each ASCII character encodes the same in UTF-8 as it does in ASCII, and every multi-byte unit in UTF-8 is guaranteed not to include any bytes in the ASCII range.


Consider upgrading to C++20 and std::u8string that is the best thing we have as of 2019 for holding UTF-8. There are no standard library facilities to access individual code points or grapheme clusters but at least your type is strong enough to at least say it is true UTF-8.

ReferenceURL : https://stackoverflow.com/questions/50403342/how-do-i-properly-use-stdstring-on-utf-8-in-c

반응형