태그 보관물: string

string

C ++의 UTF-8에서 std :: string을 올바르게 사용하려면 어떻게해야합니까? 플랫폼은 Mac입니다. 저는 C ++ 초보자이며

내 플랫폼은 Mac입니다. 저는 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 조회의 핵심 개념은 정규화와 데이터 정렬입니다. 이것은 모든 비교 작업에 영향을 미칩니다. std::string언어 또는 용도에 특정한 비교 규칙에 관계없이 항상 바이트별로 비교 (따라서 정렬)합니다. 전체 정규화 / 데이터 정렬을 처리해야하는 경우 ICU와 같은 완전한 유니 코드 라이브러리가 필요합니다.


답변

std::string친구들은 인코딩에 구애받지 않습니다. 유일한 차이 std::wstringstd::string그있는 std::wstring용도 wchar_t, 개별 소자로서 없다 char. 대부분의 컴파일러에서 후자는 8 비트입니다. 전자는 유니 코드 문자를 담을 수있을만큼 충분히 커야하지만 실제로 일부 시스템에서는 그렇지 않습니다 (예를 들어 Microsoft의 컴파일러는 16 비트 유형을 사용합니다). UTF-8을 저장할 수 없습니다 std::wstring. 그것은 그것이 설계된 것이 아닙니다. 각 요소가 단일 유니 코드 코드 포인트 인 문자열 인 UTF-32와 동일하게 설계되었습니다.

UTF-8 문자열을 유니 코드 코드 포인트 또는 구성된 유니 코드 글리프 (또는 다른 것)로 색인화하거나 유니 코드 코드 포인트 또는 기타 유니 코드 객체에서 UTF-8 문자열의 길이를 계산하거나 유니 코드 코드 포인트로 찾으려면 다음과 같습니다. 표준 라이브러리가 아닌 다른 것을 사용해야합니다. ICU 는 현장의 도서관 중 하나입니다. 다른 것이있을 수 있습니다.

주목할 가치가있는 것은 ASCII 문자를 검색하는 경우 대부분 UTF-8 바이트 스트림을 바이트 단위 인 것처럼 처리 할 수 ​​있다는 것입니다. 각 ASCII 문자는 ASCII에서와 마찬가지로 UTF-8로 인코딩되며 UTF-8의 모든 멀티 바이트 단위는 ASCII 범위의 바이트를 포함하지 않습니다.


답변

std::string 및 둘 다 std::wstring유니 코드를 나타 내기 위해 UTF 인코딩을 사용해야합니다. 특히 macOS에서는 std::stringUTF-8 (8 비트 코드 단위)이고 std::wstring UTF-32 (32 비트 코드 단위)입니다. 의 크기 wchar_t는 플랫폼에 따라 다릅니다.

두 가지 모두 size코드 포인트 수 또는 자소 클러스터 대신 코드 단위 수를 추적합니다. (코드 포인트는 이름이 지정된 유니 코드 엔티티로, 그 중 하나 이상이 자소 클러스터를 형성합니다. 자소 클러스터는 사용자가 문자 또는 이모 지와 같이 상호 작용하는 눈에 보이는 문자입니다.)

중국어의 유니 코드 표현에 익숙하지 않지만 UTF-32를 사용할 때 코드 단위의 수는 종종 자소 클러스터의 수와 매우 비슷할 수 있습니다. 그러나 이것은 최대 4 배 더 많은 메모리를 사용하는 비용으로 발생합니다.

가장 정확한 솔루션은 ICU와 같은 유니 코드 라이브러리를 사용하여 원하는 유니 코드 속성을 계산하는 것입니다.

마지막으로, 문자 결합을 사용하지 않는 인간 언어의 UTF 문자열은 일반적으로 find/ 와 잘 작동 regex합니다. 중국어는 잘 모르겠지만 영어도 그중 하나입니다.


답변

C ++ 20으로 업그레이드하는 것을 고려하십시오. std::u8string이것이 UTF-8을 보유하기 위해 2019 년 현재 가장 좋은 것입니다. 개별 코드 포인트 또는 자소 클러스터에 액세스 할 수있는 표준 라이브러리 기능은 없지만 적어도 귀하의 유형은 적어도 진정한 UTF-8이라고 말할만큼 강력합니다.


답변

계속 진행 std::string하거나로 전환해야 std::wstring합니까?

이식이 불가능하고 C ++ 20 이 표준에서 제대로 지원되지 않고 시스템 API에서 전혀 지원되지 std::string않기 때문에 사용하는 것이 좋습니다 (호환성 이유 때문일 가능성이 전혀 없음). macOS를 포함한 대부분의 플랫폼에서 일반 문자열을 사용 하는 것은 이미 UTF-8입니다.wchar_tchar8_tchar

대부분의 표준 문자열 연산은 UTF-8에서 작동하지만 코드 단위에서 작동합니다 . 더 높은 수준의 API를 원한다면 Boost에 제안 된 텍스트 라이브러리 와 같은 다른 것을 사용해야합니다 .


답변