.NET的String.Normalize是做什么用的?

91

MSDN关于String.Normalize的文章简单地说明:

返回一个新字符串,其二进制表示采用特定的Unicode规范形式。

有时还会提到“Unicode规范形式C”。

我想知道这是什么意思?这个功能在实际生活中有什么用处?


5
+1 很好的问题,我自己也很好奇。 - Adam Houldsworth
4个回答

88

表格C和表格D之间的一个区别是重音字母的表示方式:表格C使用单个带重音的代码点,而表格D将其分为字母和重音。

例如,“à”可以是代码点224(“带重音的拉丁小写字母A”),也可以是代码点97(“拉丁小写字母A”)后跟代码点786(“组合重音符号”)。逐字符比较会将它们视为不同。规范化使比较成功。

副作用是这使得轻松创建“去除重音”的方法成为可能。

public static string RemoveAccents(string input)
{
    return new string(input
        .Normalize(System.Text.NormalizationForm.FormD)
        .Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
        .ToArray());
    // the normalization to FormD splits accented letters in letters+accents
    // the rest removes those accents (and other non-spacing characters)
    // and creates a new string from the remaining chars
}

或者让“高度安全”的ROT13编码支持重音符号:

string Rot13(string input)
{
    var v = input.Normalize(NormalizationForm.FormD)
        .Select(c => {
            if ((c>='a' && c<='m') || (c>='A' && c<='M'))
                return (char)(c+13);
            if ((c>='n' && c<='z') || (c>='N' && c<='Z'))
                return (char)(c-13);
            return c;
        });
    return new String(v.ToArray()).Normalize(NormalizationForm.FormC);
}

这将把“Crème brûlée”转换为“Per̀zr oeĥyŕr”(当然,反之亦然),首先将带有重音的字符代码点分成单独的“字符”和“重音”代码点(FormD),然后仅对字母执行ROT13翻译,最后尝试重新组合它们(FormC)。

2
RemoveAccents方法中,你其实不需要.ToCharArray(),因为string类本身就是一个IEnumerable<char>(你在Rot13方法中也利用了它)。 - Jeppe Stig Nielsen

57

它确保Unicode字符串可以进行比较,即使它们使用不同的Unicode编码也是如此。

来自Unicode标准附录 #15

基本上,Unicode标准化算法将所有组合标记按照指定的顺序排列,并使用分解和组合规则将每个字符串转换为Unicode标准化形式之一。然后对转换后的字符串进行二进制比较以确定等效性。


非常好的回答。提供的链接很棒! - GeReV

7
在Unicode中,一个(组合)字符可以有一个唯一的码点,或者由基本字符和它的附加符号序列组成的码点序列。 Wikipedia列举了越南语ế(U+1EBF)及其分解的序列U+0065(e)U+0302(脱字符)U+0301(重音符)。
string.Normalize()可以在Unicode编码中转换字符串的4种标准形式。

5

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