【问题标题】:RegexOptions.CultureInvariant not finding matches for accents [duplicate]RegexOptions.CultureInvariant 找不到口音匹配项[重复]
【发布时间】:2017-04-09 14:39:23
【问题描述】:

我想创建一个忽略重音的正则表达式。

例如:

string s = "I am an old élephant";
string pattern = "elephant";
bool result = new Regex(pattern, RegexOptions.CultureInvariant).IsMatch(s);

我测试时的文化是:

System.Globalization.CultureInfo.CurrentCulture = Fr-fr

所以我本以为这段代码会找到匹配项,但事实并非如此。

有没有简单的方法来匹配这个?

我正在尝试创建一个 StringReplace 重载方法,将 élèphânt 替换为大象等。

【问题讨论】:

标签: c# regex


【解决方案1】:

使用以下方法:

    public string removeDiacritics(string str)
    {
        var sb = new StringBuilder();

        foreach (char c in str.Normalize(NormalizationForm.FormD))
        {
            if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
            {
                sb.Append(c);
            }
        }
        return sb.ToString().Normalize(NormalizationForm.FormC);
    }

然后就可以了

        string s = "I am an old élephant";
        string pattern = "elephant";
        bool result = new Regex(pattern, RegexOptions.IgnoreCase).IsMatch(removeDiacritics(s)); //true

如果您必须更换某些东西,例如迭代(向后)匹配集合并根据每个匹配项的索引编辑原始字符串。

说明:(我用的是“I am an old élephant”字符串)

让我们将原始字符串的所有字符写入一个列表:

foreach (char c in str)
{
    chars1.Add(c);
}

如您所见,char 定义为 unicode char 233 或 00E9(请参阅 http://unicode-table.com/de/#00E9

这里解释了规范化 https://msdn.microsoft.com/en-us/library/system.text.normalizationform(v=vs.110).aspx

正如文档所说: 表格 D:

Indicates that a Unicode string is normalized using full canonical decomposition.

这意味着 char é 被“拆分”为一个 e 和一个重音字符。

为了检查这一点,让我们输出标准化字符串的字符:

List<char> chars2 = new List<char>();
foreach(char c in str.Normalize(NormalizationForm.FormD))
{
    chars2.Add(c);
}

正如手表中所见,é 现在被规范化为 2 个字符(101 (\u0065) + 769 (\u0301))

现在我们必须消除这些重音: 遍历规范化字符串的所有字符,如果它是“NonSpacingMark”,则将其添加到 StringBuilder。

MSDN: https://msdn.microsoft.com/en-us/library/system.globalization.unicodecategory(v=vs.110).aspx

非间距标记

指示对基本字符进行修改的非空格字符。 由 Unicode 名称“Mn”(标记,非空格)表示。这 值为 5。

最后,为了确保所有其他字符(现在在我们的字符串中定义为 2 或 3 个字符)都“转换”为 unicode 字符符号,我们必须将新字符串规范化回 FormC。

MSDN: C型:

表示使用完整规范对 Unicode 字符串进行规范化 分解,然后用它们的序列替换 如果可能的话,使用初级复合材料。

【讨论】:

  • 那行得通。谢谢这个:)
  • @user1519979:也许你应该详细说明一下它是如何工作的。我明白你在做什么,但我不确定每个人都这样做......
  • @Sefe 完成.. ;)
  • 不错............
【解决方案2】:

如果您想使用正则表达式,您可以使用\P{L} 来声明给定的 unicode 字符是一个字母。

        string s = "I am an old ùûüÿàâçéèêëïîô";
        string pattern = @"(\p{L})";
        var regex = new Regex(pattern);
        var result = regex.Replace(s, @"$1");
        Console.WriteLine(result);//I am an old uuuyaaceeeeiio

【讨论】:

    【解决方案3】:

    您正在指定一个 CultureIn 变体正则表达式。这意味着您的文化被忽略。因此,您要么必须删除该选项...

    bool result = new Regex(pattern).IsMatch(s);
    

    ...或者,如果您想独立于文化,请扩展您的模式:

    string pattern = "[eé]lephant";
    

    【讨论】:

    • 默认,没有 RegexOptions.CultureInvariant,它不起作用。我的理解是 RegexOptions.CultureInvariant 标签会使其匹配,但我误解了。
    • 字符串模式 = "[eé]lephant";不是我正在寻找的,因为我正在寻找一种通用方法来在将带有重音的字符串与没有重音的字符串进行比较时找到匹配项。我实际上是在尝试创建一个 StringReplace 重载方法,将 élèphânt 替换为大象等。
    • 如果您想这样做,请使用String.Equals。您可以在那里指定您的文化。正则表达式将帮助您进行精确匹配;对于文化敏感的搜索,它不是很有用。您还应该更新您的问题以提供此类信息,否则您将无法获得所需的信息。
    猜你喜欢
    • 2020-01-30
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 2012-02-20
    • 2017-10-11
    • 2019-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多