儘管在論壇上關於unicode和字符串轉換(在C/C++中)以及谷歌搜索了幾個小時的話題,仍然找不到對我看來像是一個非常基本的過程的直接解釋。這是我想要做的:字符串到Unicode和Unicode到十進制代碼點(C++)
我有一個字符串,它可能使用任何可能的語言的任何字符。以西里爾文爲例。所以說我有:
std::string str = "сапоги";
我想遍歷每個字符組成該字符串和:
- 知道/打印字符的Unicode值
- 轉換是Unicode值的十進制值
我真的谷歌搜索幾個小時,並找不到直接的答案。如果有人能告訴我如何做到這一點,那會很好。
編輯
所以我設法得到那麼遠:
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <locale>
#include <codecvt>
#include <iomanip>
// utility function for output
void hex_print(const std::string& s)
{
std::cout << std::hex << std::setfill('0');
for(unsigned char c : s)
std::cout << std::setw(2) << static_cast<int>(c) << ' ';
std::cout << std::dec << '\n';
}
int main()
{
std::wstring test = L"сапоги";
std::wstring_convert<std::codecvt_utf16<wchar_t>> conv1;
std::string u8str = conv1.to_bytes(test);
hex_print(u8str);
return 1;
}
結果:
04 41 04 30 04 3f 04 3e 04 33 04 38
哪個是正確的(它映射到Unicode)。問題是我不知道我是否應該使用utf-8,16或其他內容(正如克里斯在評論中指出的那樣)。有沒有一種方法可以找到這個問題? (無論編碼它最初使用或需要使用的任何編碼?)
EDIT 2
我想我會解決一些與第二編輯評論:
「轉換的是Unicode值到十進制值「爲什麼?
我會解釋爲什麼,但我也想以友好的方式發表評論,我的問題不是'爲什麼',而是'如何';-)。你可以假設OP有提出這個問題的理由,但是當然,我知道人們爲什麼好奇......所以讓我解釋一下。我之所以需要這一切,是因爲我最終需要從字體文件中讀取字形(TrueType OpenType無關緊要)。碰巧這些文件有一個名爲cmap
的表,它是某種類型的關聯數組,將字符的值(在代碼點上的表單中)映射到字體文件中字形的索引。表中的代碼點沒有使用符號U + XXXX定義,而是直接在該數字的小數對應中定義(假設U + XXXX表示法是uint16數字的十六進制表示法[或者如果大於uint16,則爲U + XXXXXX但更多在那之後])。因此總之,西里爾語([gueu])中的字母г
具有代碼點值U+0433
,其十進制形式是1075
。我需要值1075
在cmap
表中進行查找。
// utility function for output
void hex_print(const std::string& s)
{
std::cout << std::hex << std::setfill('0');
uint16_t i = 0, dec;
for(unsigned char c : s) {
std::cout << std::setw(2) << static_cast<int>(c) << ' ';
dec = (i++ % 2 == 0) ? (c << 8) : (dec | c);
printf("Unicode Value: U+%04x Decimal value of code point: %d\n", codePoint, codePoint);
}
}
的std :: string被編碼無關。它基本上存儲字節。 std :: wstring很奇怪,雖然也沒有被定義爲保存任何特定的編碼。在Windows中,wchar_t用於UTF-16
是的,我想當你理解「while」時你認爲(至少我做過)字符串只是存儲「ASCII」字符(在此處保留) ,這似乎是錯誤的。事實上,std :: string只是註釋中的字節。雖然很明顯,如果你看一下串english
的字節你:
std::string eng = "english";
hex_print(eng);
65 6e 67 6c 69 73 68
,如果你做「同樣的事情сапоги你:
std::string cyrillic = "сапоги";
hex_print(cyrillic);
d1 81 d0 b0 d0 bf d0 be d0 b3 d0 b8
我真的很想知道/理解是如何隱式完成這種轉換?爲什麼UTF-8編碼在這裏而不是UTF-16,並且是否有可能改變(或者是由我的IDE或OS定義的)?顯然,當我複製粘貼字符串在我的文本編輯器中,它實際上已經複製了一個12字節的數組(這12個字節可能是utf-8或utf-16)
我認爲Unicode和編碼之間存在混淆。 Codepoint(AFAIK)只是一個字符代碼。 UTF 16給你的代碼,所以你可以說你的0x0441是西里爾小寫字母的情況下的一個代碼點。據我瞭解,UTF16與Unicode代碼點一對一映射,其範圍爲1M和某些字符。但是,其他編碼技術(例如UTF-8)不會直接映射到Unicode代碼點。所以我猜,你最好堅持使用UTF-16
沒錯!我發現這個評論確實非常有用。因爲是的,在編碼Unicode代碼點值的方式與Unicode值本身無關的事實方面存在着混淆(而且我感到困惑),很好,因爲事實上,事情可能會誤導我,因爲我會現在顯示。 You can indeed encode the string сапоги
using UTF8 and you will get:
d1 81 d0 b0 d0 bf d0 be d0 b3 d0 b8
所以很明顯它無關確實字形的Unicode值。現在,如果你使用UTF-16編碼相同的字符串你:
04 41 04 30 04 3f 04 3e 04 33 04 38
其中04和41是真的信с
(西里爾[SE])的兩個字節(十六進制形式)。至少在這種情況下,unicode值和其uint16表示形式之間存在直接映射關係。這就是爲什麼(每維基的解釋 [source]):
兩個UTF-16和UCS-2在該範圍內爲單16位代碼的單位,在數值上等於相應的碼點編碼的代碼點。
但是正如有人在評論中提出的那樣,某些代碼點值超出了可以用2個字節定義的值。例如:
1D307 TETRAGRAM FOR FULL CIRCLE(Tai Xuan Jing Symbols)
這正是該評論是在暗示:
據我所知,除非你使用代理UTF-16並沒有涵蓋所有的字符對。它意味着原來,當65K是綽綽有餘,但出去的窗口,使之成爲一個非常尷尬的選擇,現在
雖然是完全準確的UTF-16一樣UTF-8 CAN編碼所有字符,儘管它可以使用最多4個字節(因爲您建議如果需要超過2個字節將使用代理對)。
我試圖使用mbrtoc32
做一個轉換爲UTF-32,但在Mac上奇怪地缺少cuchar
。
順便說一句,如果你不知道什麼是surrogate pair
是(我沒有)有a nice post about this on the forum。
你想使用像'std :: string str = L「сапоги」'? –
我不知道。我的目標是找到組成字符串的每個字符的Unicode值,並將其轉換爲十進制值。 – user18490
這是一個很好的閱讀:http://reedbeta.com/blog/programmers-intro-to-unicode/ – tntxtnt