2012-12-08 27 views
1

我有一個任意的Unicode字符串,表示一個數字,例如「2」,「2」(U + 0662,ARABIC-INDIC DIGIT TWO)或「Ⅱ」(U + 2161,ROMAN NUMERAL TWO)。我想將該字符串轉換爲一個int。我不關心特定的語言環境(輸入可能不在當前語言環境中);如果它是一個有效的數字,那麼它應該被轉換。將任何Unicode字符串轉換爲int

我試過QString.toIntQLocale.toInt,但他們似乎沒有完成工作。例如:

bool ok; 
int n; 
QString s = QChar(0x0662); // ARABIC-INDIC DIGIT TWO 

n = s.toInt(&ok); // n == 0; ok == false 

QLocale anyLocale(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); 
n = anyLocale.toInt(s, &ok); // n == 0; ok == false 

QLocale cLocale = QLocale::C; 
n = cLocale.toInt(s, &ok); // n == 0; ok == false 

QLocale arabicLocale = QLocale::Arabic; // Specific locale. I don't want that. 
n = arabicLocale.toInt(s, &ok); // n == 2; ok == true 

有我缺少一個功能?

我可以嘗試所有語言環境:

QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); 
for(int i = 0; i < allLocales.size(); i++) 
{ 
    n = allLocales[i].toInt(s, &ok); 
    if(ok) 
     break; 
} 

但是,這感覺稍微的hackish。此外,它不適用於所有字符串(例如羅馬數字,但這是一個可以接受的限制)。這樣做時是否有任何缺陷,例如不同地區的衝突規則(參見土耳其語與非土耳其語信件的規則)?

+0

在不知道輸入語言環境的情況下執行此操作可能很危險。如果相同的字符在不同的語言環境中表示不同的數字值會發生什麼?我們不知道所有的語言,這就是爲什麼我們不能假設它們中沒有一個具有不同含義的重疊數字字符串。 –

+0

這是假設的,還是有這樣的情況的實例? –

+0

這只是沒有任何意義。如果你看到一個說英語的用戶輸入一個字符與一箇中文數字相匹配,那麼不要*假設他學會了如何說漢語並掌握使用IME。假設他輸入了錯誤的數據,即99.9%的情況。 –

回答

4

我」不知道任何現成的用包,它做到這一點(但 也許ICU支持它),但如果你真的想要 ,這並不難。首先,您應該從http://www.unicode.org/Public/UNIDATA/UnicodeData.txt下載UnicodeData.txt文件 。 這是一個易於解析的ASCII文件;在http://www.unicode.org/reports/tr44/tr44-10.html, 中描述的確切語法爲 ,但出於您的目的,您只需要知道 中的每行都包含分號分隔的字段。第一個 字段包含十六進制的字符代碼,第三個字段爲 「通用類別」,如果第三個字段爲「Nd」(數字, 十進制),則第七個字段包含十進制值。

該文件可以使用Python或其他一些 腳本語言輕鬆解析,以構建映射表。你會想要一些稀疏表示,因爲有超過一百萬個 Unicode字符,其中很少(幾百)是十進制數字 。以下Python腳本將爲您提供C++ 表,該表可用於初始化 std::map<int, int>;。如果地圖中的字符爲 ,映射的元素就是其值。

這是否足夠取決於您的應用程序。 它有幾個弱點:

  • 它需要額外的邏輯在兩次連續 數字是在不同的字母來識別。推測應該將序列"1١" 視爲兩個數字(1和1),而不是一個 (11)。 (因爲所有的組十進制數字都在10個 連續代碼,這將是相當容易的,一旦你知道了 位,檢查前面的數字字符是否在 同一組。)

  • 它忽略非十進制數字,如௰或൱(泰米爾語十和 馬來亞語一百)。它們中沒有那麼多,並且它們也是在UnicodeData.txt文件中的 ,所以它可能可以通過 手動找到它們並將它們添加到表中。我自己並不知道 ,但是,當編號爲 時,它們如何與其他數字結合。

  • 如果你正在轉換數字,你可能不得不擔心 的方向。我不知道這是如何處理的(但在Unicode網站有 文檔);一般來說,文本將按其自然順序出現 。在阿拉伯語中的情況和相關的 語言,在自然順序讀取時,低位 數字出現第一:像"١٢"(字面"12", 但因爲寫作是從右到左,該數字將 出現在訂單"21")應解釋爲12,而不是21.除此之外,我不確定是否存在改變方向標記是否爲 。 (確切的規則是在統一站點 文檔中描述;在UnicodeData.txt文件, 第五場—指數4 —給出了這樣的信息,我認爲 如果它是什麼,但"AN",您可以假設大端。 。在歐洲使用 標準,但我不知道)

只是爲了說明如何簡單,這是,這裏的Python腳本 解析UnicodeData.txt文件數位值:

print('std::pair<int, int> initUnicodeMap[] = {') 
for line in open("UnicodeData.txt"): 
    fields = line.split(';') 
    if fields[2] == 'Nd': 
     print(' {{{:d}, {:d}}},'.format(int(fields[0], 16), int(fields[7]))) 
print('};') 

如果你使用Unicode做任何工作,這個文件是一個金礦 用於生成各種有用的表格。

+1

實際上,即使在從右到左的段落中,阿拉伯數字也會從左到右放在內存中。這使[BiDi](http://www.unicode.org/reports/tr9/)文本佈局更有趣,但轉換爲數字更容易。 – rodrigo

+1

我的回答已經涵蓋了這其實(這輪並不需要至少在PHP,JAVA,QT或C#來重新改造),問題是unicode的不歸類中國數字作爲數字 – Esailija

+0

我很欣賞你的勤奮,但作爲Esailija寫道,數字值已經在Qt中可用。 :) –

2

您可以使用方法QChar::digitValue得到一個Unicode字符的數字等效:

int value = QChar::digitValue((uint)0x0662); 

它將返回-1如果字符沒有數值。

documentation,如果你需要更多的幫助,我真的不知道很多關於C++/QT


在維基百科的文章中提到中國數字屬於0x4E00-0x9FCC。有個別字沒有有用的元數據,在此範圍內:

4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;; 
9FCC;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; 

所以,如果你想給中國的數字映射到整數,你必須做你自己的映射,就這麼簡單。

這裏的維基百科文章中的符號的簡單映射在一個單一的符號映射到一些單號:

0x96f6,0x3007 = 0 
0x58f9,0x4e00,0x5f0c = 1 
0x8cb3,0x8d30,0x4e8c,0x5f0d,0x5169,0x4e24 = 2 
0x53c3,0x53c1,0x4e09,0x5f0e,0x53c3,0x53c2,0x53c4,0x53c1 = 3 
0x8086,0x56db,0x4989 = 4 
0x4f0d,0x4e94 = 5 
0x9678,0x9646,0x516d = 6 
0x67d2,0x4e03 = 7 
0x634c,0x516b = 8 
0x7396,0x4e5d = 9 
0x62fe,0x5341,0x4ec0 = 10 
0x4f70,0x767e = 100 
0x4edf,0x5343 = 1000 
0x842c,0x842c,0x4e07 = 10000 
0x5104,0x5104,0x4ebf = 100000000 

0x5e7a = 1 
0x5169,0x4e24 = 2 
0x5440 = 10 
0x5ff5,0x5eff = 20 
0x5345 = 30 
0x534c = 40 
0x7695 = 200 

0x6d1e = 0 
0x5e7a = 1 
0x4e24 = 2 
0x5200 = 4 
0x62d0 = 7 
0x52fe = 9 
+0

好找,但這隻會爲包含數字編號的工作,像http://en.wikipedia.org/wiki/Chinese_numerals –

+0

@SebastianNegraszus不是數符號很好,是的,它僅適用於那些已經被列爲數字以unicode標準 – Esailija