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

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

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


s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase);
s1.Equals(s2, StringComparison.OrdinalIgnoreCase);

这两个字符串需要相同(就我的应用程序而言) ,但是这两个语句的计算结果都是 false。在 C # 中有办法做到这一点吗?

82010 次浏览

在 String.Compare 方法上尝试此重载。

比较方法(String,String,Boolean,CultureInfo)

它基于包括 cultureinfo 在内的比较操作生成一个 int 值。页面中的示例比较 en-US 和 en-CZ 中的“ Change”。在 en-CZ 中的 CH 是一个单独的“字母”。

例子从链接

using System;
using System.Globalization;


class Sample {
public static void Main() {
String str1 = "change";
String str2 = "dollar";
String relation = null;


relation = symbol( String.Compare(str1, str2, false, new CultureInfo("en-US")) );
Console.WriteLine("For en-US: {0} {1} {2}", str1, relation, str2);


relation = symbol( String.Compare(str1, str2, false, new CultureInfo("cs-CZ")) );
Console.WriteLine("For cs-CZ: {0} {1} {2}", str1, relation, str2);
}


private static String symbol(int r) {
String s = "=";
if      (r < 0) s = "<";
else if (r > 0) s = ">";
return s;
}
}
/*
This example produces the following results.
For en-US: change < dollar
For cs-CZ: change > dollar
*/

因此,对于重音语言,您需要获得区域性,然后根据区域性测试字符串。

Http://msdn.microsoft.com/en-us/library/hyxc48dt.aspx

下面的方法 CompareIgnoreAccents(...)可以处理示例数据

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)));
}

我认为扩展方法会更好:

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)));
}

那么它的作用就是:

if(string.Compare(s1.RemoveAccents(), s2.RemoveAccents(), true) == 0) {
...

FWIW,Knightfor 的回答以下(本文写作时)应该是可接受的答案。

下面是一个从字符串中去除变音符的函数:

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);
}

更多详情 在米奇卡普的博客上(安息吧。)。

原理是它把‘ é’转换成2个连续的字符‘ e’,锐化。 然后它遍历字符并跳过变音符。

“你好”变成了“他 < 急性 > 你好”,这又变成了“你好”。

Debug.Assert("hello"==RemoveDiacritics("héllo"));

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

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

如果不需要转换字符串,只需检查是否相等,可以使用

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


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

或者如果您希望对比也是不区分大小写的

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


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

我必须用 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;
}

对于一个班轮怪胎;)

    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;
}

口音激励和案件激励都可以这样称呼

value.ToString().StartsWith(str, CultureInfo.InvariantCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase)

一种更简单的去除重音的方法:

    Dim source As String = "áéíóúç"
Dim result As String


Dim bytes As Byte() = Encoding.GetEncoding("Cyrillic").GetBytes(source)
result = Encoding.ASCII.GetString(bytes)