C # स्विच स्टेटमेंट का उपयोग कैसे करें IgnoreCase का उपयोग करें


92

अगर मेरे पास एक स्विच-केस स्टेटमेंट है, जहां स्विच में ऑब्जेक्ट स्ट्रिंग है, तो क्या एक Ignasease तुलना करना संभव है?

मेरे पास उदाहरण के लिए है:

string s = "house";
switch (s)
{
  case "houSe": s = "window";
}

विल sमूल्य "विंडो" मिल सकता है? मैं स्विच-केस स्टेटमेंट को कैसे ओवरराइड कर सकता हूं ताकि यह इग्निसकेस का उपयोग करके स्ट्रिंग्स की तुलना करेगा?

जवाबों:


64

जैसा कि आप जानते हैं, दो स्ट्रिंग्स को कम करना और उनकी तुलना करना इग्नोर-केस की तुलना करने जैसा नहीं है। इसके कई कारण हैं। उदाहरण के लिए, यूनिकोड मानक पाठविज्ञान को कई तरीकों से कूटबद्ध करने की अनुमति देता है। कुछ वर्णों में आधार चरित्र और एकल कोड बिंदु में विशेषक दोनों शामिल हैं। इन वर्णों का प्रतिनिधित्व आधार वर्ण के रूप में भी किया जा सकता है, जिसके बाद एक संयोजन वर्णक वर्ण भी होता है। ये दो अभ्यावेदन सभी उद्देश्यों के लिए समान हैं, और .NET फ्रेमवर्क में कल्चर-अवेलेबल स्ट्रिंग कंपेरिजन या इनटैरिकल्चर (इग्नोरकैस के साथ या बिना) के साथ, समान रूप से उनकी सही पहचान करेंगे। दूसरी ओर, एक क्रमिक तुलना, उन्हें गलत रूप से असमान मान लेगी।

दुर्भाग्य से, switchकुछ भी नहीं करता है , लेकिन एक क्रमिक तुलना। कुछ प्रकार के अनुप्रयोगों के लिए एक क्रमिक तुलना ठीक है, जैसे कठोर परिभाषित कोड वाली ASCII फ़ाइल को पार्स करना, लेकिन अधिकांश अन्य उपयोगों के लिए क्रमिक स्ट्रिंग तुलना गलत है।

मैंने सही व्यवहार प्राप्त करने के लिए अतीत में जो किया है वह मेरे स्वयं के स्विच स्टेटमेंट का मजाक उड़ा रहा है। ऐसा करने के बहुत सारे तरीके हैं। एक तरीका List<T>केस स्ट्रिंग्स और डेलिगेट्स के जोड़े बनाने का होगा । सूची को उचित स्ट्रिंग तुलना का उपयोग करके खोजा जा सकता है। जब मैच मिल जाता है तो संबंधित प्रतिनिधि को आमंत्रित किया जा सकता है।

एक अन्य विकल्प ifबयानों की स्पष्ट श्रृंखला करना है । यह आमतौर पर उतना बुरा नहीं होता जितना लगता है, क्योंकि संरचना बहुत नियमित है।

इसके बारे में महान बात यह है कि स्ट्रिंग्स के खिलाफ तुलना करने पर अपनी स्वयं की स्विच कार्यक्षमता को मॉक करने में वास्तव में कोई प्रदर्शन जुर्माना नहीं है। सिस्टम एक पूर्णांक के साथ ओ (1) जंप टेबल बनाने के लिए नहीं जा रहा है, इसलिए यह किसी भी समय एक स्ट्रिंग की तुलना करने जा रहा है।

यदि कई मामलों की तुलना की जानी है, और प्रदर्शन एक मुद्दा है, तो List<T>ऊपर वर्णित विकल्प को एक हल शब्दकोश या हैश तालिका से बदला जा सकता है। फिर प्रदर्शन संभावित रूप से स्विच स्टेटमेंट विकल्प से मेल खा सकता है या अधिक हो सकता है।

यहाँ प्रतिनिधियों की सूची का एक उदाहरण है:

delegate void CustomSwitchDestination();
List<KeyValuePair<string, CustomSwitchDestination>> customSwitchList;
CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound);
void CustomSwitch(string value)
{
    foreach (var switchOption in customSwitchList)
        if (switchOption.Key.Equals(value, StringComparison.InvariantCultureIgnoreCase))
        {
            switchOption.Value.Invoke();
            return;
        }
    defaultSwitchDestination.Invoke();
}

बेशक, आप शायद कुछ मानक मापदंडों को जोड़ना चाहेंगे और संभवत: CustomSwitchDestination प्रतिनिधि को एक वापसी प्रकार। और आप बेहतर नाम बनाना चाहते हैं!

यदि आपके प्रत्येक मामले का व्यवहार इस तरह से मंगलाचरण को सौंपने के लिए उत्तरदायी नहीं है, जैसे कि यदि अलग-अलग पैरामीटर आवश्यक हैं, तो आप जंजीरों से बंधे हुए हैं if। मैंने भी कुछ बार ऐसा किया है।

    if (s.Equals("house", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "window";
    }
    else if (s.Equals("business", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "really big window";
    }
    else if (s.Equals("school", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "broken window";
    }

6
जब तक मैं गलत नहीं हूँ, दोनों केवल कुछ संस्कृतियों (जैसे तुर्की) के लिए अलग हैं, और इस मामले में वह उपयोग नहीं कर सकता ToUpperInvariant()या ToLowerInvariant()? इसके अलावा, वह दो अज्ञात तारों की तुलना नहीं कर रहा है , वह एक अज्ञात स्ट्रिंग की एक ज्ञात स्ट्रिंग से तुलना कर रहा है। इस प्रकार, जब तक वह जानता है कि उपयुक्त ऊपरी या निचले मामले के प्रतिनिधित्व को हार्डकोड कैसे किया जाए तो स्विच ब्लॉक को ठीक काम करना चाहिए।
सेठ पेट्री-जॉनसन

8
@ सेठ पेट्री-जॉनसन - शायद वह अनुकूलन किया जा सकता है, लेकिन इसका कारण यह है कि स्ट्रिंग तुलना विकल्प को फ्रेमवर्क में बेक किया जाता है, इसलिए हम सभी को सही, एक्स्टेंसिबल सॉफ्टवेयर लिखने के लिए भाषा विज्ञान के विशेषज्ञ नहीं बनना चाहिए।
जेफरी एल व्हाइटलेज

59
ठीक। मैं एक उदाहरण दूंगा जहां यह निश्चिंत है। मान लीजिए कि "घर" के बजाय हमारे पास (अंग्रेजी!) शब्द "कैफे" था। इस मान को "कैफ़े \ u00E9" या "कैफ़े \ u0301" द्वारा समान रूप से अच्छी तरह से (और समान रूप से) का प्रतिनिधित्व किया जा सकता है। साधारण समानता (एक स्विच स्टेटमेंट में) ToLower()या तो ToLowerInvariant()झूठे के साथ वापस आ जाएगी। सच के Equalsसाथ StringComparison.InvariantCultureIgnoreCaseवापस आ जाएगी। चूंकि दोनों अनुक्रम प्रदर्शित होने पर समान दिखते हैं, इसलिए ToLower()संस्करण नीचे ट्रैक करने के लिए एक बुरा बग है। यही कारण है कि यह हमेशा उचित स्ट्रिंग तुलना करने के लिए सबसे अच्छा है, भले ही आप तुर्की न हों।
जेफरी एल व्हाइटलेज

78

स्विच स्टेटमेंट में जाने से पहले एक सरल तरीका आपके स्ट्रिंग को कम कर रहा है, और मामलों को कम करना है।

वास्तव में, ऊपरी एक शुद्ध चरम नैनोसेकंड प्रदर्शन के दृष्टिकोण से थोड़ा बेहतर है, लेकिन देखने में कम प्राकृतिक है।

उदाहरण के लिए:

string s = "house"; 
switch (s.ToLower()) { 
  case "house": 
    s = "window"; 
    break;
}

1
हां, मैं समझता हूं कि लोअरकेसिंग एक तरीका है, लेकिन मैं चाहता हूं कि इसे इग्नोर किया जाए। क्या कोई ऐसा तरीका है जिससे मैं स्विच-केस स्टेटमेंट को ओवरराइड कर सकता हूं?
टॉलसन

6
@ लाजर - यह सीएलआर के माध्यम से सी # के माध्यम से है, इसे यहां कुछ समय पहले ही छिपी हुई फीचर थ्रेड में भी पोस्ट किया गया था: stackoverflow.com/questions/9033/hidden-features-of-c/… आप कुछ के साथ LinqPad को आग लगा सकते हैं मिलियन पुनरावृत्तियों, सही है।
निक Craver

1
@ टॉलसन - नहीं, दुर्भाग्य से यह सिर्फ स्थैतिक प्रकृति के कारण नहीं है। यह एक पर जवाब का एक अच्छा बैच था समय पहले: stackoverflow.com/questions/44905/...
निक Craver

9
ऐसा प्रतीत होता है ToUpper(Invariant)कि न केवल तेज है, बल्कि अधिक विश्वसनीय है: stackoverflow.com/a/2801521/67824
Ohad श्नाइडर


48

एक पुराने प्रश्न के लिए इस नई पोस्ट के लिए क्षमा करें, लेकिन C # 7 (VS 2017) का उपयोग करके इस समस्या को हल करने के लिए एक नया विकल्प है।

C # 7 अब "पैटर्न मिलान" प्रदान करता है, और इसका उपयोग इस मुद्दे को संबोधित करने के लिए किया जा सकता है:

string houseName = "house";  // value to be tested, ignoring case
string windowName;   // switch block will set value here

switch (true)
{
    case bool b when houseName.Equals("MyHouse", StringComparison.InvariantCultureIgnoreCase): 
        windowName = "MyWindow";
        break;
    case bool b when houseName.Equals("YourHouse", StringComparison.InvariantCultureIgnoreCase): 
        windowName = "YourWindow";
        break;
    case bool b when houseName.Equals("House", StringComparison.InvariantCultureIgnoreCase): 
        windowName = "Window";
        break;
    default:
        windowName = null;
        break;
}

यह समाधान @ जेफ्री एल व्हिटलेज द्वारा उत्तर में वर्णित मुद्दे से भी संबंधित है कि तार के मामले-असंवेदनशील तुलना दो निचले आवरण वाले तार की तुलना के समान नहीं है।

वैसे, दृश्य स्टूडियो पत्रिका में फरवरी 2017 में एक दिलचस्प लेख था जिसमें पैटर्न मिलान का वर्णन किया गया था और इसे केस ब्लॉक में कैसे उपयोग किया जा सकता है। कृपया देखें: C # 7.0 केस ब्लॉक में पैटर्न मिलान

संपादित करें

@ लुईसएम के उत्तर के प्रकाश में, यह बताना महत्वपूर्ण है कि switchकथन में कुछ नया, दिलचस्प व्यवहार है। वह यह है कि यदि आपके caseकथन में एक चर घोषणा है, तो switchभाग में निर्दिष्ट मूल्य को घोषित चर में कॉपी किया जाता है case। निम्नलिखित उदाहरण में, मान trueको स्थानीय चर में कॉपी किया जाता है b। इसके अलावा, चर bअप्रयुक्त है, और केवल मौजूद है ताकि बयान का whenखंड caseमौजूद हो सके:

switch(true)
{
    case bool b when houseName.Equals("X", StringComparison.InvariantCultureIgnoreCase):
        windowName = "X-Window";):
        break;
}

जैसा कि @LewisM बताता है, इसका उपयोग लाभ के लिए किया जा सकता है - कि लाभ होने की बात यह है कि तुलना की जा रही बात वास्तव में switchबयान में है, क्योंकि यह कथन के शास्त्रीय उपयोग के साथ switchहै। इसके अलावा, caseबयान में घोषित अस्थायी मूल्य मूल मूल्य के अवांछित या अनजाने परिवर्तनों को रोक सकते हैं:

switch(houseName)
{
    case string hn when hn.Equals("X", StringComparison.InvariantCultureIgnoreCase):
        windowName = "X-Window";
        break;
}

2
यह अधिक लंबा होगा, लेकिन मैं इसके switch (houseName)बाद आपके द्वारा किए गए तरीके की तुलना करना पसंद करूंगा , जैसेcase var name when name.Equals("MyHouse", ...
लुईसएम

@LewisM - यह दिलचस्प है। क्या आप इसका एक कार्यशील उदाहरण दिखा सकते हैं?
STLDev

@LewisM - शानदार जवाब। मैंने अस्थायी वैरिएबल के switchलिए तर्क मान असाइन करने पर और चर्चा की है case
STLDev

आधुनिक सी # में मिलान पैटर्न के लिए या #
थियागो सिल्वा

आप "ऑब्जेक्ट पैटर्न मिलान" का उपयोग भी कर सकते हैं, case { } whenताकि आपको चर प्रकार और नाम के बारे में चिंता न करनी पड़े।
बॉब

33

कुछ मामलों में एनम का उपयोग करना एक अच्छा विचार हो सकता है। तो पहले एनम (अनदेखी के साथ ध्वज सच) को पार्स करें और एनम पर स्विच करें।

SampleEnum Result;
bool Success = SampleEnum.TryParse(inputText, true, out Result);
if(!Success){
     //value was not in the enum values
}else{
   switch (Result) {
      case SampleEnum.Value1:
      break;
      case SampleEnum.Value2:
      break;
      default:
      //do default behaviour
      break;
   }
}

बस एक नोट: Enum TryParse फ्रेमवर्क 4.0 और आगे, FYI के साथ उपलब्ध है। msdn.microsoft.com/en-us/library/dd991317(v=vs.100).aspx
granadaCoder

4
मैं इस समाधान को पसंद करता हूं क्योंकि यह जादू के तारों के उपयोग को हतोत्साहित करता है।
user1069816

23

@STLDeveloperA द्वारा उत्तर के लिए एक विस्तार। एकाधिक के बिना स्टेटमेंट मूल्यांकन करने का एक नया तरीका अगर c # 7 के रूप में स्टेटमेंट पैटर्न मिलान स्विच स्टेटमेंट का उपयोग कर रहा है, तो @STLDeveloper के तरीके के समान है, हालांकि यह तरीका स्विच किए जा रहे चर पर स्विच कर रहा है

string houseName = "house";  // value to be tested
string s;
switch (houseName)
{
    case var name when string.Equals(name, "Bungalow", StringComparison.InvariantCultureIgnoreCase): 
        s = "Single glazed";
    break;

    case var name when string.Equals(name, "Church", StringComparison.InvariantCultureIgnoreCase):
        s = "Stained glass";
        break;
        ...
    default:
        s = "No windows (cold or dark)";
        break;
}

दृश्य स्टूडियो पत्रिका में पैटर्न मिलान केस ब्लॉक पर एक अच्छा लेख है जो देखने लायक हो सकता है।


नए switchकथन की अतिरिक्त कार्यक्षमता को इंगित करने के लिए धन्यवाद ।
STLDev

5
+1 - यह आधुनिक (C # 7 आगे) विकास के लिए स्वीकृत उत्तर होना चाहिए। एक बदलाव जो मैं करूंगा वह यह है कि मैं इस तरह से कोड करूंगा: case var name when "Bungalow".Equals(name, StringComparison.InvariantCultureIgnoreCase):क्योंकि यह एक अशक्त संदर्भ अपवाद (जहां houseName शून्य है) को रोक सकता है, या वैकल्पिक रूप से स्ट्रिंग के लिए एक मामला जोड़ सकता है।
Jay

21

एक संभव तरीका एक कार्रवाई प्रतिनिधि के साथ एक अनदेखी मामले शब्दकोश का उपयोग करना होगा।

string s = null;
var dic = new Dictionary<string, Action>(StringComparer.CurrentCultureIgnoreCase)
{
    {"house",  () => s = "window"},
    {"house2", () => s = "window2"}
};

dic["HouSe"]();

// ध्यान दें कि कॉल पाठ को वापस नहीं करता है, लेकिन केवल स्थानीय चर को पॉप्युलेट करता है।
// यदि आप वास्तविक पाठ को वापस करना चाहते हैं, तो कुछ की तरह शब्दकोश में मूल्यों और मूल्यों Actionको बदलेंFunc<string>() => "window2"


4
बजाय CurrentCultureIgnoreCase, OrdinalIgnoreCaseपसंद किया जाता है।
रिचर्ड ईव

2
@richardEverett पसंदीदा? निर्भर करता है कि आप क्या चाहते हैं, यदि आप वर्तमान संस्कृति को अनदेखा करना चाहते हैं तो यह पसंद नहीं है।
मैग्नस

अगर किसी की दिलचस्पी है, तो मेरा समाधान (नीचे) इस विचार को लेता है और इसे एक साधारण वर्ग में लपेटता है।
फ्लाईडॉग57

2

यहाँ एक समाधान है कि एक वर्ग में @Magnus समाधान लपेटता है:

public class SwitchCaseIndependent : IEnumerable<KeyValuePair<string, Action>>
{
    private readonly Dictionary<string, Action> _cases = new Dictionary<string, Action>(StringComparer.OrdinalIgnoreCase);

    public void Add(string theCase, Action theResult)
    {
        _cases.Add(theCase, theResult);
    }

    public Action this[string whichCase]
    {
        get
        {
            if (!_cases.ContainsKey(whichCase))
            {
                throw new ArgumentException($"Error in SwitchCaseIndependent, \"{whichCase}\" is not a valid option");
            }
            //otherwise
            return _cases[whichCase];
        }
    }

    public IEnumerator<KeyValuePair<string, Action>> GetEnumerator()
    {
        return _cases.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _cases.GetEnumerator();
    }
}

यहां एक साधारण विंडोज फॉर्म के ऐप में इसका उपयोग करने का एक उदाहरण दिया गया है:

   var mySwitch = new SwitchCaseIndependent
   {
       {"hello", () => MessageBox.Show("hello")},
       {"Goodbye", () => MessageBox.Show("Goodbye")},
       {"SoLong", () => MessageBox.Show("SoLong")},
   };
   mySwitch["HELLO"]();

यदि आप लैम्ब्डा (उदाहरण के लिए) का उपयोग करते हैं, तो आपको क्लोजर मिलते हैं जो आपके स्थानीय वैरिएबल्स को कैप्चर करेंगे (जो आपको एक स्विच स्टेटमेंट से प्राप्त होने वाली भावना के बहुत करीब है)।

चूंकि यह कवर के तहत एक डिक्शनरी का उपयोग करता है, इसलिए इसे ओ (1) व्यवहार मिलता है और स्ट्रिंग्स की सूची के माध्यम से चलने पर भरोसा नहीं करता है। बेशक, आपको उस शब्दकोश का निर्माण करने की आवश्यकता है, और शायद इसकी लागत अधिक है।

यह शायद एक सरल bool ContainsCase(string aCase)विधि को जोड़ने के लिए समझ में आता है जो केवल शब्दकोश की ContainsKeyविधि को कहता है ।


1

मुझे उम्मीद है कि यह पूरे मामले को विशेष रूप से कम मामले या ऊपरी मामले में बदलने की कोशिश करता है और तुलना के लिए लोअरकेस स्ट्रिंग का उपयोग करता है:

public string ConvertMeasurements(string unitType, string value)
{
    switch (unitType.ToLower())
    {
        case "mmol/l": return (Double.Parse(value) * 0.0555).ToString();
        case "mg/dl": return (double.Parse(value) * 18.0182).ToString();
    }
}

0

यह करने के लिए पर्याप्त होना चाहिए:

string s = "houSe";
switch (s.ToLowerInvariant())
{
  case "house": s = "window";
  break;
}

स्विच तुलना जिससे संस्कृति अपरिवर्तनीय है। जहाँ तक मैं देख सकता हूँ यह सी # 7 पैटर्न-मिलान समाधान के समान परिणाम प्राप्त करना चाहिए, लेकिन अधिक संक्षेप में।


-1

10 साल बाद, सी # पैटर्न मिलान के साथ, आप कुछ ऐसा कर सकते हैं:

private string NormalisePropertyType(string propertyType) => true switch
{
    true when string.IsNullOrWhiteSpace(propertyType) => propertyType,
    true when "house".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "house",
    true when "window".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "window",
    true when "door".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "door",
    true when "roof".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "roof",
    true when "chair".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "chair",
    _ => propertyType
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.