我有一个代表数字的任意Unicode字符串,例如“2”,“2”(U + 0662,ARABIC-INDIC DIGIT TWO)或“Ⅱ”(U + 2161,ROMAN NUMERAL TWO)。我想将该字符串转换为int。我不关心特定的语言环境(输入可能不在当前语言环境中);如果它是一个有效的数字,那么它应该被转换。
我尝试了QString.toInt
和QLocale.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;
}
但这感觉有些迟钝。此外,它不适用于所有字符串(例如罗马数字,但这是一个可接受的限制)。这样做是否存在任何陷阱,例如不同语言环境中的冲突规则(参见土耳其语与非土耳其语字母案例规则)?
答案 0 :(得分:4)
我不知道任何准备使用的包这样做(但是 也许ICU支持它),但如果你真的这么做并不难 想要。首先,您应该下载UnicodeData.txt文件 来自http://www.unicode.org/Public/UNIDATA/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。除了我不确定更改方向标记是否是
是否在场。 (确切的规则在中描述
Unicode站点的文档;在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 :(得分: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