忽略字符串比较中的重音字母

Jon*_*ury 128 c# string localization

我需要比较C#中的2个字符串,并将重音字母与非重音字母相同.例如:

string s1 = "hello";
string s2 = "héllo";

s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase);
s1.Equals(s2, StringComparison.OrdinalIgnoreCase);
Run Code Online (Sandbox Code Playgroud)

这两个字符串需要相同(就我的应用程序而言),但这两个语句都评估为false.C#中有没有办法做到这一点?

Ser*_*ier 237

编辑2012-01-20:哦,孩子!解决方案非常简单,几乎永远存在于框架中.正如knightpfhor所指出的那样:

string.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace);
Run Code Online (Sandbox Code Playgroud)

这是一个从字符串中删除变音符号的函数:

static string RemoveDiacritics(string text)
{
  string formD = text.Normalize(NormalizationForm.FormD);
  StringBuilder sb = new StringBuilder();

  foreach (char ch in formD)
  {
    UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(ch);
    if (uc != UnicodeCategory.NonSpacingMark)
    {
      sb.Append(ch);
    }
  }

  return sb.ToString().Normalize(NormalizationForm.FormC);
}
Run Code Online (Sandbox Code Playgroud)

关于MichKap博客的更多细节(RIP ......).

原则是它将'é'变成2个连续的字符'e',是急性的.然后它遍历字符并跳过变音符号.

"héllo"变成了"他<acute> llo",而后者变成了"你好".

Debug.Assert("hello"==RemoveDiacritics("héllo"));
Run Code Online (Sandbox Code Playgroud)

注意:这是一个更紧凑的.NET4 +友好版本的相同功能:

static string RemoveDiacritics(string text)
{
  return string.Concat( 
      text.Normalize(NormalizationForm.FormD)
      .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch)!=
                                    UnicodeCategory.NonSpacingMark)
    ).Normalize(NormalizationForm.FormC);
}
Run Code Online (Sandbox Code Playgroud)

  • 由于.net core没有“string.Normalize”,如何在.net core中执行此操作? (3认同)

kni*_*hor 126

如果您不需要转换字符串,并且只想检查是否可以使用

string s1 = "hello";
string s2 = "héllo";

if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace) == 0)
{
    // both strings are equal
}
Run Code Online (Sandbox Code Playgroud)

或者如果您希望比较也不区分大小写

string s1 = "HEllO";
string s2 = "héLLo";

if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0)
{
    // both strings are equal
}
Run Code Online (Sandbox Code Playgroud)

  • 如果其他人对这个 IgnoreNonSpace 选项感到好奇,您可能想阅读有关它的讨论。http://www.pcreview.co.uk/forums/accent-insensitive-t3924592.html TLDR;没关系 :) (3认同)
  • 这是因为通常SQL Server配置为不区分大小写,但默认情况下.Net中的比较区分大小写.我已经更新了答案,以说明如何使这种情况不敏感. (2认同)

Gui*_*ish 6

我不得不做类似的事情,但使用 StartsWith 方法。这是一个从@Serge 派生的简单解决方案 - appTranslator。

这是一个扩展方法:

    public static bool StartsWith(this string str, string value, CultureInfo culture, CompareOptions options)
    {
        if (str.Length >= value.Length)
            return string.Compare(str.Substring(0, value.Length), value, culture, options) == 0;
        else
            return false;            
    }
Run Code Online (Sandbox Code Playgroud)

对于一个班轮怪胎;)

    public static bool StartsWith(this string str, string value, CultureInfo culture, CompareOptions options)
    {
        return str.Length >= value.Length && string.Compare(str.Substring(0, value.Length), value, culture, options) == 0;
    }
Run Code Online (Sandbox Code Playgroud)

Accent incensitive 和 case incensitive startsWith 可以这样调用

value.ToString().StartsWith(str, CultureInfo.InvariantCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase)
Run Code Online (Sandbox Code Playgroud)


Rya*_*ook 5

以下方法CompareIgnoreAccents(...)适用于您的示例数据.以下是我获取背景信息的文章:http://www.codeproject.com/KB/cs/EncodingAccents.aspx

private static bool CompareIgnoreAccents(string s1, string s2)
{
    return string.Compare(
        RemoveAccents(s1), RemoveAccents(s2), StringComparison.InvariantCultureIgnoreCase) == 0;
}

private static string RemoveAccents(string s)
{
    Encoding destEncoding = Encoding.GetEncoding("iso-8859-8");

    return destEncoding.GetString(
        Encoding.Convert(Encoding.UTF8, destEncoding, Encoding.UTF8.GetBytes(s)));
}
Run Code Online (Sandbox Code Playgroud)

我认为扩展方法会更好:

public static string RemoveAccents(this string s)
{
    Encoding destEncoding = Encoding.GetEncoding("iso-8859-8");

    return destEncoding.GetString(
        Encoding.Convert(Encoding.UTF8, destEncoding, Encoding.UTF8.GetBytes(s)));
}
Run Code Online (Sandbox Code Playgroud)

然后使用将是这样的:

if(string.Compare(s1.RemoveAccents(), s2.RemoveAccents(), true) == 0) {
   ...
Run Code Online (Sandbox Code Playgroud)

  • 这是一种破坏性的比较,例如ā和ē将被视为平等.你松开0xFF以上的任何字符,并且不能保证字符串是等于忽略的重音. (4认同)
  • 这使得重音字母变成“?” (2认同)