簡體   English   中英

循環通過 Unicode 字符串作為字符

[英]Loop through Unicode string as character

使用以下字符串,大小不正確的是 output。 為什么會這樣,我該如何解決?

string str = " ██████";
cout << str.size();
// outputs 19 rather than 7

我正在嘗試逐個字符地循環str以便我可以將其讀入一個大小應該為 7 的vector<string> ,但我不能這樣做,因為上面的代碼輸出 19。

TL;博士

basic_stringsize()length()成員以底層字符串為單位返回大小,而不是可見字符數 要獲得預期的數字:

  • 對不包含非 BMP、不組合字符和不連接字符的非常簡單的字符串使用帶有u前綴的 UTF-16
  • 對不包含任何組合或連接字符的非常簡單的字符串使用帶有U前綴的 UTF-32
  • 規范化任意 Unicode 字符串的字符串和計數

" ██████"是一個空格,后面跟着一系列 6 個U+2588個字符。 您的編譯器似乎將UTF-8用於std::string UTF-8 是一種可變長度編碼,許多字母使用多個字節進行編碼(因為顯然你不能用一個字節編碼超過 256 個字符)。 在 UTF-8 中,U+0800 和 U+FFFF 之間的代碼點由 3 個字節編碼。 因此 UTF-8 中字符串的長度為1 + 6*3 = 19個字節。

您可以使用任何 Unicode 轉換器進行檢查,並查看字符串在 ZAE3B3DF9970B49B6573E608759 中的每個字節編碼為20 E2 96 88 E2 96 88 E2 96 88 E2 96 88 E2 96 88 E2 96 88要檢查的字符串

如果您想要字符串可見字符的總數,那么它會更加棘手,並且churill 的解決方案不起作用 閱讀Twitter中的示例

如果你使用最基本的字母、數字和標點符號之外的任何東西,情況就會變得更加混亂。 雖然許多人使用多字節漢字字符來舉例說明這些問題,但 Twitter 發現重音元音會引起最大的混亂,因為說英語的人只是希望它們能起作用。 舉個例子:“咖啡館”這個詞。 事實證明,有兩個字節序列看起來完全相同,但使用的字節數不同:

 café 0x63 0x61 0x66 0xC3 0xA9 Using the “é” character, called the “composed character”. café 0x63 0x61 0x66 0x65 0xCC 0x81 Using the combining diacritical, which overlaps the “e”

您需要一個像ICU這樣的 Unicode 庫來規范化字符串和計數。 Twitter 例如使用規范化表格 C

編輯:

由於您只對似乎不在 BMP 之外且不包含任何組合字符的框繪圖字符感興趣,因此 UTF-16 和 UTF-32 將起作用。 std::string一樣, std::wstring也是一個basic_string並且沒有強制編碼。 在大多數實現中,它通常是 UTF-16 (Windows) 或 UTF-32 (*nix),因此您可以使用它,但它不可靠並且取決於源代碼編碼。 更好的方法是使用std::u16string ( std::basic_string<char16_t> ) 和std::u32string ( std::basic_string<char32_t> )。 無論源文件的系統和編碼如何,它們都可以工作

std::wstring wstr     = L" ██████";
std::u16string u16str = u" ██████";
std::u32string u32str = U" ██████";
std::cout << str.size();    // may work, returns the number of wchar_t characters
std::cout << u16str.size(); // always returns the number of UTF-16 code units
std::cout << u32str.size(); // always returns the number of UTF-32 code units

如果您對如何解決所有 Unicode 字符感興趣,請繼續閱讀下文

上面提到的“café”問題引發了如何計算 Tweet 字符串“café”中的字符的問題。 對人眼來說,長度顯然是四個字符。 根據數據的表示方式,這可能是五個或六個 UTF-8 字節。 Twitter 不想因為我們使用 UTF-8 或因為有問題的 API 客戶端使用更長的表示而懲罰用戶。 因此,無論發送哪種表示形式,Twitter 都將“café”計為四個字符。

[...]

Twitter 使用文本的規范化表格 C (NFC) 版本計算推文的長度。 這種類型的規范化有利於使用完全組合的字符(咖啡館示例中的 0xC3 0xA9)而不是長格式版本(0x65 0xCC 0x81)。 Twitter 還計算文本中的代碼點數,而不是 UTF-8 字節數。 咖啡館示例中的 0xC3 0xA9 是一個代碼點 (U+00E9),在 UTF-8 中編碼為兩個字節,而 0x65 0xCC 0x81 是兩個代碼點,編碼為三個字節

Twitter - 計數字符

也可以看看

std::string僅包含 1 字節長字符(通常為 8 位,包含 UTF-8 字符),您需要wchar_tstd::wstring來實現您想要的:

std::wstring str = L" ██████";
std::cout << str.size();

盡管這會打印 7(一個空格和 6 個 unicode 字符)。 請注意字符串文字前的 L,因此它將被解釋為寬字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM