[c#] “유사한”유니 코드 문자를 비교하는 방법은 무엇입니까?

나는 놀라운 문제에 빠진다.

내 응용 프로그램에 텍스트 파일을로드했고 µ 값을 비교하는 논리가 있습니다.

그리고 나는 텍스트가 동일하더라도 비교 값이 거짓임을 깨달았습니다.

 Console.WriteLine("μ".Equals("µ")); // returns false
 Console.WriteLine("µ".Equals("µ")); // return true

뒷줄에서 문자 µ는 복사 붙여 넣기됩니다.

그러나 이것들은 이와 같은 유일한 캐릭터가 아닐 수도 있습니다.

C #에서 동일하게 보이지만 실제로 다른 문자를 비교할 수있는 방법이 있습니까?



답변

많은 경우에, 당신은 할 수 있습니다 정상화 를 비교하기 전에 특정 정상화 폼에 유니 코드 문자를 모두, 그들은 일치 할 수 있어야한다. 물론 어떤 정규화 형식을 사용해야하는지는 문자 자체에 따라 다릅니다. 단지 그들이 때문에 필요가 같은 문자를 나타내는 의미하지 않는다 모두. 또한 사용 사례에 적합한 지 고려해야합니다. Jukka K. Korpela의 의견을 참조하십시오.

이 특정 상황에서 Tony ‘s answer 의 링크를 참조하면 U + 00B5에 대한 표에 다음과 같은 내용이 표시됩니다 .

분해 <compat> GREEK SMALL LETTER MU (U + 03BC)

즉, 원래 비교에서 두 번째 문자 인 U + 00B5를 첫 번째 문자 인 U + 03BC로 분해 할 수 있습니다.

따라서 정규화 형식 KC 또는 KD와 함께 완전한 호환성 분해를 사용하여 문자를 정규화합니다. 다음은 내가 시연하기 위해 작성한 간단한 예입니다.

using System;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        char first = 'μ';
        char second = 'µ';

        // Technically you only need to normalize U+00B5 to obtain U+03BC, but
        // if you're unsure which character is which, you can safely normalize both
        string firstNormalized = first.ToString().Normalize(NormalizationForm.FormKD);
        string secondNormalized = second.ToString().Normalize(NormalizationForm.FormKD);

        Console.WriteLine(first.Equals(second));                     // False
        Console.WriteLine(firstNormalized.Equals(secondNormalized)); // True
    }
}

유니 코드 정규화 및 다양한 정규화 형식에 대한 자세한 내용은 System.Text.NormalizationForm유니 코드 사양을 참조하십시오 .


답변

똑같아도 정말 다른 기호이기 때문에 첫 번째는 실제 문자이고 char가 code = 956 (0x3BC)있고 두 번째는 마이크로 기호이며 181 (0xB5).

참조 :

따라서 이들을 비교하고 동일해야하는 경우 수동으로 처리하거나 비교하기 전에 한 문자를 다른 문자로 대체해야합니다. 또는 다음 코드를 사용하십시오.

public void Main()
{
    var s1 = "μ";
    var s2 = "µ";

    Console.WriteLine(s1.Equals(s2));  // false
    Console.WriteLine(RemoveDiacritics(s1).Equals(RemoveDiacritics(s2))); // true 
}

static string RemoveDiacritics(string text)
{
    var normalizedString = text.Normalize(NormalizationForm.FormKC);
    var stringBuilder = new StringBuilder();

    foreach (var c in normalizedString)
    {
        var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
        if (unicodeCategory != UnicodeCategory.NonSpacingMark)
        {
            stringBuilder.Append(c);
        }
    }

    return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}

그리고 데모


답변

둘 다 다른 문자 코드를 가지고 있습니다. 자세한 내용은 이것을 참조하십시오.

Console.WriteLine((int)'μ');  //956
Console.WriteLine((int)'µ');  //181

첫 번째는 다음과 같습니다.

Display     Friendly Code   Decimal Code    Hex Code    Description
====================================================================
μ           &mu;            &#956;          &#x3BC;     Lowercase Mu
µ           &micro;         &#181;          &#xB5;      micro sign Mu

영상


답변

μ(mu) 및 µ(마이크로 기호) 의 특정 예의 경우 후자는 전자에 대한 호환성 분해 가 있으므로 문자열을 정규화FormKC 하거나 FormKD마이크로 기호를 mus로 변환 할 수 있습니다 .

그러나 비슷해 보이지만 유니 코드 정규화 형식에서는 동일하지 않은 문자 집합이 많이 있습니다. 예를 들어, A(Latin), Α(Greek) 및 А(Cyrillic)입니다. 유니 코드 웹 사이트에는 개발자들이 동형 이의어 공격으로부터 보호 할 수 있도록 돕기 위해 이들 목록 이 포함 된 confusables.txt 파일이 있습니다. 필요한 경우이 파일을 구문 분석하고 문자열의 “시각적 정규화”를위한 테이블을 만들 수 있습니다.


답변

유니 코드 데이터베이스 에서 두 문자를 모두 검색 하고 차이점을 확인하십시오 .

하나는 그리스 소문자 µ 이고 다른 하나는 마이크로 기호 µ 입니다.

Name            : MICRO SIGN
Block           : Latin-1 Supplement
Category        : Letter, Lowercase [Ll]
Combine         : 0
BIDI            : Left-to-Right [L]
Decomposition   : <compat> GREEK SMALL LETTER MU (U+03BC)
Mirror          : N
Index entries   : MICRO SIGN
Upper case      : U+039C
Title case      : U+039C
Version         : Unicode 1.1.0 (June, 1993)

Name            : GREEK SMALL LETTER MU
Block           : Greek and Coptic
Category        : Letter, Lowercase [Ll]
Combine         : 0
BIDI            : Left-to-Right [L]
Mirror          : N
Upper case      : U+039C
Title case      : U+039C
See Also        : micro sign U+00B5
Version         : Unicode 1.1.0 (June, 1993)


답변

편집 이 질문을 C #에서 ‘μ’와 ‘µ’를 비교하는 방법 과 병합 한 후
게시 된 원래 답변 :

 "μ".ToUpper().Equals("µ".ToUpper()); //This always return true.

편집
주석을 읽은 후에는 다른 유형의 입력에 대해 잘못된 결과를 제공 할 수 있기 때문에 위의 방법을 사용하는 것은 좋지 않습니다.이 때문에 위키 에서 언급 한대로 완전한 호환성 분해를 사용하여 정규화 를 사용해야합니다 . ( BoltClock이 게시 한 답변에 감사드립니다 )

    static string GREEK_SMALL_LETTER_MU = new String(new char[] { '\u03BC' });
    static string MICRO_SIGN = new String(new char[] { '\u00B5' });

    public static void Main()
    {
        string Mus = "µμ";
        string NormalizedString = null;
        int i = 0;
        do
        {
            string OriginalUnicodeString = Mus[i].ToString();
            if (OriginalUnicodeString.Equals(GREEK_SMALL_LETTER_MU))
                Console.WriteLine(" INFORMATIO ABOUT GREEK_SMALL_LETTER_MU");
            else if (OriginalUnicodeString.Equals(MICRO_SIGN))
                Console.WriteLine(" INFORMATIO ABOUT MICRO_SIGN");

            Console.WriteLine();
            ShowHexaDecimal(OriginalUnicodeString);
            Console.WriteLine("Unicode character category " + CharUnicodeInfo.GetUnicodeCategory(Mus[i]));

            NormalizedString = OriginalUnicodeString.Normalize(NormalizationForm.FormC);
            Console.Write("Form C Normalized: ");
            ShowHexaDecimal(NormalizedString);

            NormalizedString = OriginalUnicodeString.Normalize(NormalizationForm.FormD);
            Console.Write("Form D Normalized: ");
            ShowHexaDecimal(NormalizedString);

            NormalizedString = OriginalUnicodeString.Normalize(NormalizationForm.FormKC);
            Console.Write("Form KC Normalized: ");
            ShowHexaDecimal(NormalizedString);

            NormalizedString = OriginalUnicodeString.Normalize(NormalizationForm.FormKD);
            Console.Write("Form KD Normalized: ");
            ShowHexaDecimal(NormalizedString);
            Console.WriteLine("_______________________________________________________________");
            i++;
        } while (i < 2);
        Console.ReadLine();
    }

    private static void ShowHexaDecimal(string UnicodeString)
    {
        Console.Write("Hexa-Decimal Characters of " + UnicodeString + "  are ");
        foreach (short x in UnicodeString.ToCharArray())
        {
            Console.Write("{0:X4} ", x);
        }
        Console.WriteLine();
    }

산출

INFORMATIO ABOUT MICRO_SIGN
Hexa-Decimal Characters of µ  are 00B5
Unicode character category LowercaseLetter
Form C Normalized: Hexa-Decimal Characters of µ  are 00B5
Form D Normalized: Hexa-Decimal Characters of µ  are 00B5
Form KC Normalized: Hexa-Decimal Characters of µ  are 03BC
Form KD Normalized: Hexa-Decimal Characters of µ  are 03BC
 ________________________________________________________________
 INFORMATIO ABOUT GREEK_SMALL_LETTER_MU
Hexa-Decimal Characters of µ  are 03BC
Unicode character category LowercaseLetter
Form C Normalized: Hexa-Decimal Characters of µ  are 03BC
Form D Normalized: Hexa-Decimal Characters of µ  are 03BC
Form KC Normalized: Hexa-Decimal Characters of µ  are 03BC
Form KD Normalized: Hexa-Decimal Characters of µ  are 03BC
 ________________________________________________________________

Unicode_equivalence로 정보를 읽는 동안 발견했습니다.

동등성 기준의 선택은 검색 결과에 영향을 줄 수 있습니다. 예를 들어 U + FB03 (ffi), ….. 그래서 U + 0066 (f)를 부분 문자열로 검색 하면 U + FB03 의 NFKC 정규화에서는 성공 하지만 U + FB03의 NFC 정규화에서는 성공 하지 못합니다 .

따라서 동등성을 비교하려면 일반적으로 FormKCNFKC 정규화 또는 NFKD 정규화를 사용해야합니다 FormKD.
모든 유니 코드 문자에 대해 더 많이 알고 싶어서별로 궁금하지 않았기 때문에 모든 유니 코드 문자를 반복하는 샘플을 만들었고 UTF-16논의하고 싶은 결과를 얻었습니다.

  • FormCFormD정규화 된 값이 동일하지 않은 문자에 대한 정보
    Total: 12,118
    Character (int value): 192-197, 199-207, 209-214, 217-221, 224-253, ..... 44032-55203
  • FormKCFormKD정규화 된 값이 동일하지 않은 문자에 대한 정보
    Total: 12,245
    Character (int value): 192-197, 199-207, 209-214, 217-221, 224-228, ..... 44032-55203, 64420-64421, 64432-64433, 64490-64507, 64512-64516, 64612-64617, 64663-64667, 64735-64736, 65153-65164, 65269-65274
  • FormCFormD정규화 된 값이 동일하지 않은 모든 문자 , there FormKCFormKD정규화 된 값도 다음 문자를 제외하고 동일하지 않습니다
    .901 '΅', 8129 '῁', 8141 '῍', 8142 '῎', 8143 '῏', 8157 '῝', 8158 '῞'
    , 8159 '῟', 8173 '῭', 8174 '΅'
  • 추가 캐릭터 그 FormKCFormKD정규화 된 값은 동등하지 않았다, 그러나 거기 FormCFormD정규화 값은 상당했다
    Total: 119
    문자 :452 'DŽ' 453 'Dž' 454 'dž' 12814 '㈎' 12815 '㈏' 12816 '㈐' 12817 '㈑' 12818 '㈒'
    12819 '㈓' 12820 '㈔' 12821 '㈕', 12822 '㈖' 12823 '㈗' 12824 '㈘' 12825 '㈙' 12826 '㈚'
    12827 '㈛' 12828 '㈜' 12829 '㈝' 12830 '㈞' 12910 '㉮' 12911 '㉯' 12912 '㉰' 12913 '㉱'
    12914 '㉲' 12915 '㉳' 12916 '㉴' 12917 '㉵' 12918 '㉶' 12919 '㉷' 12920 '㉸' 12921 '㉹' 12922 '㉺' 12923 '㉻' 12924 '㉼' 12925 '㉽' 12926 '㉾' 13056 '㌀' 13058 '㌂' 13060 '㌄' 13063 '㌇' 13070 '㌎' 13071 '㌏' 13072 '㌐' 13073 '㌑' 13075 '㌓' 13077 '㌕' 13080 '㌘' 13081 '㌙' 13082 '㌚' 13086 '㌞' 13089 '㌡' 13092 '㌤' 13093 '㌥' 13094 '㌦' 13099 '㌫' 13100 '㌬' 13101 '㌭' 13102 '㌮' 13103 '㌯' 13104 '㌰' 13105 '㌱' 13106 '㌲' 13108 '㌴' 13111 '㌷' 13112 '㌸' 13114 '㌺' 13115 '㌻' 13116 '㌼' 13117 '㌽' 13118 '㌾' 13120 '㍀' 13130 '㍊' 13131 '㍋' 13132 '㍌' 13134 '㍎' 13139 '㍓' 13140 '㍔' 13142 '㍖' .......... ﺋ' 65164 'ﺌ' 65269 'ﻵ' 65270 'ﻶ' 65271 'ﻷ' 65272 'ﻸ' 65273 'ﻹ' 65274'
  • 정규화 할 수없는 문자가 있습니다.ArgumentException 시도하면 던집니다.
    Total:2081
    Characters(int value): 55296-57343, 64976-65007, 65534

이 링크는 유니 코드 동등성에 적용되는 규칙을 이해하는 데 매우 유용 할 수 있습니다.

  1. Unicode_equivalence
  2. Unicode_compatibility_characters


답변

대부분의 경우 동일한 문자를 (가시적으로) 만드는 두 가지 다른 문자 코드가 있습니다. 기술적으로 동일하지는 않지만 동일하게 보입니다. 캐릭터 테이블을보고 해당 캐릭터의 여러 인스턴스가 있는지 확인하십시오. 또는 코드에있는 두 문자의 문자 코드를 인쇄하십시오.