将任何Unicode字符串转换为int

时间:2012-12-08 18:18:42

标签: c++ qt unicode numbers

我有一个代表数字的任意Unicode字符串,例如“2”,“2”(U + 0662,ARABIC-INDIC DIGIT TWO)或“Ⅱ”(U + 2161,ROMAN NUMERAL TWO)。我想将该字符串转换为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;
}

但这感觉有些迟钝。此外,它不适用于所有字符串(例如罗马数字,但这是一个可接受的限制)。这样做是否存在任何陷阱,例如不同语言环境中的冲突规则(参见土耳其语与非土耳其语字母案例规则)?

2 个答案:

答案 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