स्ट्रिंग तुलना में उच्चारण अक्षरों को अनदेखा करना


141

मुझे C # में 2 स्ट्रिंग्स की तुलना करने की आवश्यकता है और उच्चारण अक्षरों को गैर-उच्चारण अक्षरों के समान माना जाता है। उदाहरण के लिए:

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

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

इन 2 तारों को समान होने की आवश्यकता है (जहां तक ​​मेरे आवेदन का संबंध है), लेकिन ये दोनों कथन गलत का मूल्यांकन करते हैं। क्या ऐसा करने का C # में कोई रास्ता है?

जवाबों:


251

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' में बदल देता है, तीव्र। यह फिर वर्णों के माध्यम से पुनरावृत्ति करता है और विकृति विज्ञान को छोड़ देता है।

"हेल्लो" बन जाता है "वह <तीव्र> ल्लो", जो बदले में "हैलो" बन जाता है।

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?
आंद्रे सोरेस

इसके लिए धन्यवाद, काश मैं एक से अधिक बार उत्थान कर पाता! हालाँकि, यह सभी उच्चारण अक्षरों को संभालता नहीं है, उदाहरण के लिए ħ, all और ø क्रमशः ओ, एच और ओ में परिवर्तित नहीं होते हैं। क्या इनको संभालने का कोई तरीका है?
एवरोहोम यिसरोएल

@AvrohomYisroel "is" एक "लैटिन स्माल लेटर एथ" है, जो एक अलग अक्षर है, न कि "ओ-विथ-एक्सेंट" या "डी-विथ-एक्सेंट"। अन्य "लैटिन स्मॉल लेटर एच विथ स्ट्रोक" और "लैटिन स्मॉल लेटर ओ विद स्ट्रोक" भी हैं, जिन्हें अलग-अलग अक्षरों में भी माना जा सकता है
हंस के

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; यह ठीक है :)
जिम डब्ल्यू का कहना है कि मोनिका

msdn पर: "यूनिकोड मानक एक नए चरित्र का निर्माण करने के लिए वर्णों के संयोजन के रूप में वर्णों को परिभाषित करता है जो आधार वर्णों के साथ संयुक्त होते हैं। वर्णों के संयोजन का निरूपण प्रस्तुत किए जाने पर स्वयं द्वारा रिक्ति स्थिति पर कब्जा नहीं करता है।"
एवलिन

ठीक है, यह विधि इन 2 स्ट्रिंग्स के लिए विफल रही: tarafli / TARAFL server हालांकि SQL सर्वर का कहना है कि जैसा होना चाहिए
मॉन्स्टरमोरपीजी

2
ऐसा इसलिए है क्योंकि आम तौर पर SQL सर्वर को असंवेदनशील होने के लिए कॉन्फ़िगर किया जाता है, लेकिन .Net में डिफ़ॉल्ट तुलना द्वारा मामला संवेदनशील होता है। मैंने इस मामले को असंवेदनशील बनाने का तरीका दिखाने के लिए जवाब अपडेट कर दिया है।
नाइटफोरह

मैं एक IEqualityComparer बनाने की कोशिश कर रहा हूँ। यह GetHashCode प्रदान करने की आवश्यकता है ... आप इसे कैसे प्राप्त करते हैं (यदि यह समान है तो इसे उसी तरह की आवश्यकता है)
येपेबाई

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
यह एक विनाशकारी तुलना है, जहां उदाहरण के लिए ā और ive को समान माना जाएगा। आप 0xFF से ऊपर के किसी भी वर्ण को ढीला करते हैं और इस बात की कोई गारंटी नहीं है कि तार समान-अनदेखी-उच्चारण हैं।
हाबिल

आप ñ जैसी चीजों को खो देते हैं। अगर आप मुझसे पूछें तो समाधान नहीं।
इग्नासियो सोलर गार्सिया

5

मुझे कुछ ऐसा ही करना था, लेकिन एक StartsWith विधि के साथ। यहां @Serge से प्राप्त एक सरल समाधान है - ऐपट्रांसलेटर।

यहाँ एक विस्तार विधि है:

    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)


-3

इस अधिभार को String.Compare Method पर आज़माएँ।

String.Compare विधि (स्ट्रिंग, स्ट्रिंग, बूलियन, CultureInfo)

यह कल्चरinfo सहित तुलनात्मक संचालन के आधार पर एक अंतर मूल्य पैदा करता है। पेज का उदाहरण एन-यूएस और एन-सीजेड में "चेंज" की तुलना करता है। सीएच इन एन-सीज़ एक एकल "पत्र" है।

उदाहरण से लिंक

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.