如何将重音字符转换为非重音字符

14

我在stackoverflow上找到了一个关于如何去除变音符号字符的答案,但您能否告诉我是否有可能将变音符号字符更改为非变音符号字符呢?

哦...还有,我想了解一下.NET(或其他替代方案如果不可行)。


当我在perl中必须这样做时,我只是有一个很长的手动维护的“tr”语句,所以祝你好运。 - Paul Tomblin
这是几个问题的重复。例如,搜索“translit”。请不要糟蹋我们的语言! - user3850
5个回答

30

由于没有人费心发布执行此操作的代码,因此在此提供:

    // \p{Mn} or \p{Non_Spacing_Mark}: 
    //   a character intended to be combined with another 
    //   character without taking up extra space 
    //   (e.g. accents, umlauts, etc.). 
    private readonly static Regex nonSpacingMarkRegex = 
        new Regex(@"\p{Mn}", RegexOptions.Compiled);

    public static string RemoveDiacritics(string text)
    {
        if (text == null)
            return string.Empty;

        var normalizedText = 
            text.Normalize(NormalizationForm.FormD);

        return nonSpacingMarkRegex.Replace(normalizedText, string.Empty);
    }
注意:需要这样做的一个重要原因是当你集成到一个只支持 ASCII 的第三方系统时,而你的数据是 Unicode 格式时。这种情况很常见。你的选择基本上有两个:删除带重音符号的字符,或者尝试从带重音符号的字符中去除重音以尽可能地保留原始输入的多数内容。显然,这不是一个完美的解决方案,但比简单地删除任何 ASCII 127 以上字符的方法要好80%。

不更改“ł”,波兰字母(会更改其他奇怪的字母,如ąćęńóśżź)。 - user1713059

11

我对另一个问题的回答中复制:

不必创建自己的表,您可以将文本转换为规范形式D,其中字符表示为基本字符加上变音符号(例如,“á”将被替换为“a”后跟一个组合的尖音符)。然后可以去除所有不是ASCII字母的内容。

表仍然存在,但现在是Unicode标准的表。

您还可以尝试使用NFKD而不是NFD,以捕获更多情况。

参考资料:


9
如果可能的话,请不要这样做。你正在毁坏我们的语言。请尝试使用音译。 - user3850
4
@hop,这里有一个例子。我有一个系统,用户可以搜索内容,大多数情况下,用户输入查询时没有使用重音符号,导致索引中的内容与查询不匹配。 - Amit Bens
3
你对搜索的理解是错误的。 - maxbeaudoin
2
@hop: "这里是美国,把你的 Unicode 带到别处去。" 数以百万计的用户不知道或不关心如何输入变音符号。如果他们找不到他们想要的东西,以他们期望的方式搜索它,他们会责怪你的应用程序。 - Iain Samuel McLean Elder
1
@hop 这是一个标题的恶作剧,我知道,但这里有一个有启发性的故事。就像你所说的,不是所有的音译都是逐字翻译的。例如,在德语中,“Düsseldorf”和“Duesseldorf”这两个名称是等价的;第二个可以在URL和电子邮件地址中使用。但对于一个不了解德语正字法的英语用户来说,他会打出“Dusseldorf”的拼写,并期待找到相同的结果。例如,谷歌知道这一点,并将它们三个都视为同义词。 - Iain Samuel McLean Elder
显示剩余7条评论

4
如果你想要做这件事,回头考虑一下为什么。如果你试图去除你认为不重要的字符差异,那么你应该看一下Unicode排序算法。这是比较字符串进行搜索或排序时忽略大小写或变音符号等差异的标准方法。
如果你计划展示修改后的文本,请考虑你的受众。你可以安全地过滤掉与区域设置有关的内容。在美国英语中,“Igloo” = “igloo”,“resume” = “résumé”,但在土耳其语中,小写字母I是ı(没有点),在法语中,cote意思是引用,côté意思是侧面,而côte意思是海岸。因此,排序语言决定了哪些差异是重要的。
如果去除变音符号是你的应用程序的正确解决方案,最安全的方法是制作自己的表格,并显式添加想要转换的字符。
可以使用Unicode分解来设计通用的自动化方法。通过这种方式,你可以将带有变音符号的字符分解为“组合”字符(变音符号)和它们组合的基本字符。过滤掉任何组合字符,你就可以得到“非变音符号”的字符。
然而,自动化方法的缺乏歧视可能会产生一些意想不到的影响。我建议在代表性文本上进行大量测试。

2
我认为这个的一个用处就是创建美观的URL。 - Tom Smykowski
当然可以。如果您有一个名为“Rändi Fay_Female Vocalist”的产品,并且需要生成一个url stub /product/something,那么您的选择基本上是用未带重音符号的a替换带重音符号的a,或者对字符串进行URL转义,留下一个丑陋的百分号。未带重音符号的a更可取。URL是机器可读的字符串,但通常很重要的是它们至少是半人类可读的。 - Ross Presser

2

一个简单的例子:

从字符串中删除变音符号:

string newString = myDiacriticsString.Normalize(NormalizationForm.FormD);

4
"ě".Normalize(NormalizationForm.FormD) 的结果不是 "e"。 - Feryt
是的,可以使用String.ToCharArray()来查看它。 - Hans Passant
就像Feryt一样,它对我也不起作用。("xxé").Normalize(NormalizationForm.FormD)返回"xxe"(如预期),但是string v = "xxé"; v.Normalize(NormalizationForm.FormD);返回"xxé"。我尝试调用v.ToCharArray()和("xxé").ToCharArray()来查看是否有任何区别,它们返回相同的数组。非常奇怪! - AFract
这不是全部的故事。NormalizationForm.FormD会移除重音符号,但它会将重音符号作为单独的字符添加。请检查ToCharArray的长度。 - paparazzo

0

我的网站从外部来源输入数据,其中有许多奇怪的字符。我编写了以下C#函数,使用正则表达式替换重音字符并去除非美国键盘字符:

    using System.Text;
    using System.Text.RegularExpressions;

    internal static string SanitizeString(string source)
    {
        return Regex.Replace(source.Normalize(NormalizationForm.FormD), @"[^A-Za-z 0-9 \.,\?'""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*", string.Empty).Trim();    
    }

希望能有所帮助。


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