153

C#で2つの文字列を比較し、アクセント付きの文字をアクセントなしの文字と同じように扱う必要があります。例えば:

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

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

これらの2つの文字列は(私のアプリケーションに関する限り)同じである必要がありますが、これらのステートメントは両方ともfalseと評価されます。これを行う方法はC#にありますか?

4

6 に答える 6

267

EDIT 2012-01-20: おいおい!ソリューションは非常にシンプルで、ほぼ永久にフレームワークに含まれていました。ナイトプフォーが指摘したように

string.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace);

文字列から分音記号を取り除く関数は次のとおりです。

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

詳細については、MichKap のブログ( RIP... ) を参照してください。

原則は、'é' を 2 つの連続する文字 'e'、鋭角に変えることです。次に、文字を繰り返し処理し、分音記号をスキップします。

"héllo" は "he<acute>llo" になり、さらに "hello" になります。

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);
}
于 2008-12-15T16:06:54.883 に答える
148

文字列を変換する必要がなく、等価性をチェックしたいだけの場合は、使用できます

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
}
于 2011-10-11T02:48:30.910 に答える
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)));
}

拡張メソッドの方が良いと思います:

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) {
   ...
于 2008-12-11T16:57:06.297 に答える
-3

String.Compareメソッドでこのオーバーロードを試してください。

String.Compareメソッド(String、String、Boolean、CultureInfo)

これは、cultureinfoを含む比較操作に基づいてint値を生成します。このページの例では、en-USとen-CZの「変更」を比較しています。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

于 2008-12-11T16:07:54.773 に答える