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


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.