如何在Ruby中将UTF8组合字符转换为单个UTF8字符?

17
一些字符,例如Unicode字符'LATIN SMALL LETTER C WITH CARON'可以编码为0xC4 0x8D,但也可以用'LATIN SMALL LETTER C'和'COMBINING CARON'的两个码点来表示,即0x63 0xcc 0x8c
更多信息请参见:http://www.fileformat.info/info/unicode/char/10d/index.htm 我想知道是否有一个库可以将'LATIN SMALL LETTER C'+'COMBINING CARON'转换为'LATIN SMALL LETTER C WITH CARON'。或者是否有一个包含这些转换的表格?

请不要考虑8位代码单元。只考虑逻辑代码点。您可以使用unicode_utils将其转换为NFC形式,但这并不能实现您想要的,因为您想要的是不可能的。 - tchrist
3个回答

8
这些转换并非总是存在的。例如,U+0063 (c) 与 U+030C (组合 háček) 的组合可以表示为单个字符,但是没有预先组合的字符代表带 háček 的小写 'w' (w̌)。
尽管如此,仍然存在可以在可能的情况下执行此组合的库。寻找一个名为 "NFC"(规范化形式:组合)的 Unicode 函数。请参见,例如:http://unicode-utils.rubyforge.org/classes/UnicodeUtils.html#M000015

7
通常,您使用Unicode标准化来完成此操作。使用unicode_utils(https://github.com/lang/unicode_utils)的UnicodeUtils.nfkc宝石将为您提供所需的特定行为; Unicode规范形式kC将使用兼容性分解,然后将字符串转换为组合形式(基本上是您通过示例要求的内容)。 (有时缩写为NFC的规范形式c也可能接近您想要的内容。)如何在Ruby 1.9上替换Unicode gem?有更多细节。在Ruby 1.8.7中,您需要安装Unicode宝石,其中有类似的功能。编辑以添加:您很可能希望使用规范形式kC而不仅仅是规范形式C的主要原因是连字号(由于历史/排版原因紧密挤在一起的字符)将首先被分解为单个字符,这在进行词典排序或搜索时有时是可取的。

3
你假设这样的预组合字符存在,但这并不是一个好的假设。请注意,U+0035 ‹5› 数字5 后面跟着 U+0304 ‹◌̄› 上长音符号 在 NFC 中没有比在 NFD 中更短的呈现形式。只有少数遗留代码点具有预组合字符,而大多数没有。 - tchrist
3
不,我说的是“如果有的话”。我没有做出任何假设。 - JasonTrue

0

自 Ruby 1.9 开始,可以使用 String#encode 方法。UTF-8-MAC 是 NFD 的一种变体。范围在 U+2000 到 U+2FFF、U+F900 到 U+FAFF 或 U+2F800 到 U+2FAFF 内的码位不会被分解。有关详细信息,请参见 https://developer.apple.com/library/mac/qa/qa1173/_index.html。也可以使用 UTF-8-HFS 替代 UTF-8-MAC。

# coding: utf-8

s = "\u010D"
s.encode!('UTF-8-MAC', 'UTF-8')
s.force_encoding('UTF-8')

p "\x63\xcc\x8c" == s
p "\u0063" == s[0]
p "\u030C" == s[1]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接