문자열 비교에서 악센트 부호 문자 무시


141

C #에서 2 개의 문자열을 비교하고 악센트 부호 문자를 비 액센트 문자와 동일하게 취급해야합니다. 예를 들면 다음과 같습니다.

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

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

이 두 문자열은 (응용 프로그램과 관련하여) 동일해야하지만이 두 문장은 모두 거짓으로 평가됩니다. C #에 이것을 할 수있는 방법이 있습니까?

답변:


251

2012-01-20 편집 : 오 소년! 이 솔루션은 훨씬 간단했고 거의 영원히 프레임 워크에있었습니다. knightpfhor가 지적한 바와 같이 :

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"는 "hecute"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);
}

1
그것이 없기 때문에 .net 코어에서 어떻게해야 string.Normalize합니까?
Andre Soares

감사합니다. 한 번 이상 공표 할 수 있기를 바랍니다. 그러나 모든 악센트 부호 문자를 처리하지는 않습니다. 예를 들어 ð, ħ 및 ø는 각각 o, h 및 o로 변환되지 않습니다. 이것들도 처리 할 수있는 방법이 있습니까?
Avrohom Yisroel 14

@AvrohomYisroel "ð"는 "라틴 소문자 Eth"입니다. "라틴 소문자 Eth"는 "o-with-accent"또는 "d-with-accent"가 아닌 별도의 문자입니다. 다른 문자로는 "Latin Small Letter H With Stroke"와 "Latin Small Letter O With Stroke"도 있습니다.
한스 케 st (Hans Ke st ing)

135

문자열을 변환 할 필요가 없으며 평등을 확인하려는 경우 사용할 수 있습니다

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
}

다른 사람이이 IgnoreNonSpace 옵션에 대해 궁금한 경우이 토론을 읽으십시오. pcreview.co.uk/forums/accent-insensitive-t3924592.html TLDR; 그것은 괜찮습니다 :)
짐 W는 모니카

on msdn : "유니 코드 표준은 결합 문자를 기본 문자와 결합하여 새 문자를 생성하는 문자로 정의합니다. 공백이없는 결합 문자는 렌더링 될 때 간격 위치 자체를 차지하지 않습니다."
Avlin

ok이 방법은 다음 두 문자열에 대해 실패했습니다. tarafli / TARAFLİ 그러나 SQL 서버는 동일하다고 가정합니다
MonsterMMORPG

2
일반적으로 SQL Server는 대소 문자를 구분하지 않지만 .Net의 기본 비교는 대소 문자를 구분하므로 구성됩니다. 대소 문자를 구분하지 않는 방법을 보여주기 위해 답변을 업데이트했습니다.
knightpfhor

IEqualityComparer를 만들려고합니다. GetHashCode를 제공해야합니다. 어떻게해야합니까 (동일한 경우 동일해야 함)
Yepeekai

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) {
   ...

1
이것은 악센트 문자를 '?'
onmyway133

4
이것은 파괴적인 비교입니다. 예를 들어 ā와 ē는 동일하게 취급됩니다. 0xFF를 초과하는 문자는 잃어 버리고 문자열이 동일한 무시 농도라는 보장은 없습니다.
Abel

ñ와 같은 것들도 잃습니다. 당신이 나에게 묻는다면 해결책이 아닙니다.
이그나시오 솔러 가르시아

5

비슷한 것을하지만 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)

0

악센트를 제거하는 더 간단한 방법 :

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

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

-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


이 방법은 문자열을 직접 비교하는 것보다 나은 방법이지만 여전히 기본 문자와 액센트 버전이 다른 것으로 간주합니다 . 따라서 악센트를 무시하고 싶었던 원래 질문에 대답하지 않습니다.
CB
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.