2010-01-27 15 views
10

में रेगुलर एक्सप्रेशन मैं सी # में निम्नलिखित है:संयोजन इन दो एक

public static bool IsAlphaAndNumeric(string s) 
{ 
    return Regex.IsMatch(s, @"[a-zA-Z]+") 
     && Regex.IsMatch(s, @"\d+"); 
} 

मैं अगर पैरामीटर s कम से कम एक अक्षर और एक अंक शामिल हैं जाँच करना चाहते हैं और मैं ऐसा करने उपरोक्त विधि लिखा था इसलिए।

लेकिन क्या कोई तरीका है कि मैं दो नियमित अभिव्यक्तियों ("[a-zA-Z]+" और "\d+") को एक साथ जोड़ सकता हूं?

+2

यदि आप केवल इनमें से कम से कम 1 सत्यापित करना चाहते हैं, तो अनावश्यक रूप से लंबी स्ट्रिंग से मेल खाने के लिए '+' ऑपरेटर का उपयोग न करें। – kennytm

+2

मुझे लगता है कि मूल संस्करण अधिकतर उत्तर से अधिक सुरुचिपूर्ण और पठनीय है। – Kobi

+3

मुझे लगता है कि इस विधि को ** HasAlphaAndNumeric ** कहा जाना चाहिए। आप केवल यह जांच रहे हैं कि इसमें * प्रत्येक में से एक है; बाकी के पात्र कुछ भी हो सकते हैं, या कुछ भी नहीं। उदाहरण के लिए, 'ए 1' और'! @ # 1%^और ए() _ 'दोनों पास - क्या आप इसका इरादा रखते हैं? –

उत्तर

9
@"^(?=.*[a-zA-Z])(?=.*\d)" 

^ # From the begining of the string 
(?=.*[a-zA-Z]) # look forward for any number of chars followed by a letter, don't advance pointer 
(?=.*\d) # look forward for any number of chars followed by a digit) 

यह एक पत्र है, और succeding से पहले एक संख्या पाता है सुनिश्चित करने के लिए दो positive lookaheads उपयोग करता है। स्ट्रिंग की शुरुआत से, आप केवल एक बार देखने की कोशिश करने के लिए ^ जोड़ें। अन्यथा, regexp इंजन स्ट्रिंग में हर बिंदु पर मिलान करने का प्रयास करेगा।

2
private static readonly Regex _regex = new Regex(
    @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$", RegexOptions.Compiled); 

public static bool IsAlphaAndNumeric(string s) 
{ 
    return _regex.IsMatch(s); 
} 

यदि आप मामले को अनदेखा करना चाहते हैं तो आप RegexOptions.Compiled | RegexOptions.IgnoreCase का उपयोग कर सकते हैं।

+0

+1 लेकिन ओपी चाहता है कि मामला असंवेदनशील लगता है। – Amarghosh

+0

ओपी के लिए, इस पृष्ठ पर सकारात्मक लुकअप देखें: http://msdn.microsoft.com/en-us/library/1400241x(VS.85).aspx –

+1

यह रेगेक्स केवल स्ट्रिंग से मेल खाता है जिसमें लोअरकेस और अपरकेस अक्षर होता है। .. –

3

आप [a-zA-Z].*[0-9]|[0-9].*[a-zA-Z] का उपयोग कर सकते हैं, लेकिन मैं केवल तभी अनुशंसा करता हूं यदि आप जिस सिस्टम का उपयोग कर रहे थे केवल एक ही रेगेक्स स्वीकार कर लिया गया हो। मैं कल्पना नहीं कर सकता कि यह बिना दो वैकल्पिक पैटर्न के दो सरल पैटर्न से अधिक कुशल होगा।

3

यह वही नहीं है जो आप चाहते हैं लेकिन कहें कि मेरे पास अधिक समय है। निम्नलिखित regex से तेजी से काम करना चाहिए।

static bool IsAlphaAndNumeric(string str) { 
     bool hasDigits = false; 
     bool hasLetters=false; 

     foreach (char c in str) { 
      bool isDigit = char.IsDigit(c); 
      bool isLetter = char.IsLetter(c); 
      if (!(isDigit | isLetter)) 
       return false; 
      hasDigits |= isDigit; 
      hasLetters |= isLetter; 
     } 
     return hasDigits && hasLetters; 
    } 

इसकी तेज़ी से इसकी जांच क्यों करें। परीक्षण स्ट्रिंग जेनरेटर निम्नलिखित है। यह 1/3 सेट पूरी तरह से सही स्ट्रिंग और 2/3 विज्ञापन गलत उत्पन्न करता है। 2/3 1/2 में सभी अल्फा और अन्य आधा सभी अंक हैं।

static IEnumerable<string> GenerateTest(int minChars, int maxChars, int setSize) { 
     string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
     string numbers = "";    
     Random rnd = new Random(); 
     int maxStrLength = maxChars-minChars; 
     float probablityOfLetter = 0.0f; 
     float probablityInc = 1.0f/setSize; 
     for (int i = 0; i < setSize; i++) { 
      probablityOfLetter = probablityOfLetter + probablityInc; 
      int length = minChars + rnd.Next() % maxStrLength; 
      char[] str = new char[length]; 
      for (int w = 0; w < length; w++) { 
       if (probablityOfLetter < rnd.NextDouble()) 
        str[w] = letters[rnd.Next() % letters.Length]; 
       else 
        str[w] = numbers[rnd.Next() % numbers.Length];      
      } 
      yield return new string(str); 
     } 
    } 

डारिन दो समाधान निम्नलिखित है। एक संकलित है और दूसरा गैर संकलित संस्करण है।

class DarinDimitrovSolution 
{ 
    const string regExpression = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$"; 
    private static readonly Regex _regex = new Regex(
     regExpression, RegexOptions.Compiled); 

    public static bool IsAlphaAndNumeric_1(string s) { 
     return _regex.IsMatch(s); 
    } 
    public static bool IsAlphaAndNumeric_0(string s) { 
     return Regex.IsMatch(s, regExpression); 
    } 

पीछा कर रहा है परीक्षण पाश

static void Main(string[] args) { 

     int minChars = 3; 
     int maxChars = 13; 
     int testSetSize = 5000; 
     DateTime start = DateTime.Now; 
     foreach (string testStr in 
      GenerateTest(minChars, maxChars, testSetSize)) { 
      IsAlphaNumeric(testStr); 
     } 
     Console.WriteLine("My solution : {0}", (DateTime.Now - start).ToString()); 

     start = DateTime.Now; 
     foreach (string testStr in 
      GenerateTest(minChars, maxChars, testSetSize)) { 
      DarinDimitrovSolution.IsAlphaAndNumeric_0(testStr); 
     } 
     Console.WriteLine("DarinDimitrov 1 : {0}", (DateTime.Now - start).ToString()); 

     start = DateTime.Now; 
     foreach (string testStr in 
      GenerateTest(minChars, maxChars, testSetSize)) { 
      DarinDimitrovSolution.IsAlphaAndNumeric_1(testStr); 
     } 
     Console.WriteLine("DarinDimitrov(compiled) 2 : {0}", (DateTime.Now - start).ToString()); 

     Console.ReadKey(); 
    } 

के बाद का मुख्य है परिणाम

My solution : 00:00:00.0170017 (Gold) 
DarinDimitrov 1 : 00:00:00.0320032 (Silver medal) 
DarinDimitrov(compiled) 2 : 00:00:00.0440044 (Gold) 

तो सबसे पहले समाधान सबसे अच्छा था। कुछ और रिलीज़ मोड में परिणाम और कल्पना

int minChars = 20; 
    int maxChars = 50; 
    int testSetSize = 100000; 

My solution : 00:00:00.4060406 
DarinDimitrov 1 : 00:00:00.7400740 
DarinDimitrov(compiled) 2 : 00:00:00.3410341 (now that very fast) 

मैं RegexOptions.IgnoreCase ध्वज के साथ फिर से जाँच की निम्नलिखित। ऊपर

My solution : 00:00:00.4290429 (almost same as before) 
DarinDimitrov 1 : 00:00:00.9700970 (it have slowed down) 
DarinDimitrov(compiled) 2 : 00:00:00.8440844 (this as well still fast but look at .3 in last result) 

बाद gnarf मेरी algo यदि स्ट्रिंग केवल और अंक पत्र से मिलकर बनता है तो मैं इसे बदल उसकी जांच करने गया था के साथ एक समस्या थी कि उल्लेख और अब यह है कि स्ट्रिंग शो की जाँच के रूप में ही परम के बाकी कम से कम एक चार है और एक अंक।

static bool IsAlphaNumeric(string str) { 
     bool hasDigits = false; 
     bool hasLetters = false; 

     foreach (char c in str) { 
      hasDigits |= char.IsDigit(c); 
      hasLetters |= char.IsLetter(c); 
      if (hasDigits && hasLetters) 
       return true; 
     } 
     return false; 
    } 

परिणाम

My solution : 00:00:00.3900390 (Goody Gold Medal) 
DarinDimitrov 1 : 00:00:00.9740974 (Bronze Medal) 
DarinDimitrov(compiled) 2 : 00:00:00.8230823 (Silver) 

मेरा एक बड़ा पहलू से तेज है।

+0

कोई औचित्य क्यों रेगेक्स से तेज़ होगा? – Amarghosh

+0

और यदि यह * तेज * है, तो अंतर छोटा होगा। इस प्रयास को लायक बनाने के लिए आपको एक तंग लूप में लाखों तारों का परीक्षण करना होगा। –

+0

मैंने प्रदर्शन परिणाम प्रकाशित किया है। मेरे जवाब में आपको समय मिल गया। – affan

10

LINQ के साथ सी # के लिए:

return s.Any(Char.IsDigit) && s.Any(Char.IsLetter); 
+1

कृपया, कोई इसे उत्तर के रूप में चिह्नित करें! – Benjol

+0

बदतर मामले में स्ट्रिंग वर्णों के दो पूर्ण पुनरावृत्ति की आवश्यकता होगी। – affan

+0

@affan - सबसे बुरे मामले में आपको हर चरित्र को दो बार जांचना होगा; यह हर संभव समाधान के लिए सच है। चाहे यह एक लूप या दो में होता है, कोई अन्य अंतर इटरेटर बनाने से अलग नहीं होता है - एक मेमोरी स्ट्रिंग के लिए, यह सबसे अधिक ओवरहेड होता है। – Kobi

0

निम्नलिखित यह भी है, न केवल अन्य अग्रदर्शी निर्माणों की तुलना में तेजी है (मेरी आँखों में) आवश्यकताओं के करीब:

[a-zA-Z\d]((?<=\d)[^a-zA-Z]*[a-zA-Z]|[^\d]*\d) 

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

चरण 1:: यह एक एक वर्ण (हमें यह कॉल) एक नंबर या एक पत्र है कि मेल खाता है

यहाँ कैसे (और क्यों) यह काम करता है है।
चरण 2: यह जांचने के लिए एक दृश्यमान है कि सी एक संख्या है। यदि ऐसा है:
चरण 2.1: यह असीमित संख्या में वर्णों की अनुमति देता है जो एक पत्र नहीं हैं, उसके बाद एक अक्षर के बाद। यदि यह मेल खाता है, तो हमारे पास एक पत्र के बाद एक संख्या (सी) है।
चरण 2.2: यदि सी कोई संख्या नहीं है, तो यह एक पत्र होना चाहिए (अन्यथा यह मिलान नहीं किया गया होगा)। इस मामले में हम एक अंक के बाद असीमित संख्या में गैर-अंकों की अनुमति देते हैं। इसका मतलब यह होगा कि हमारे पास एक पत्र है (सी) इसके बाद एक संख्या है।

+0

तार्किक रूप से यह बेनामी 'उत्तर के समान है, लेकिन अधिक जटिल है। क्या आप वाकई जल्दी हैं? असफल होने के मामले में, क्या यह प्रत्येक मिलान पत्र के लिए परीक्षण नहीं करेगा? (उदाहरण के लिए, 600 'एक्स) – Kobi

+0

@ एफ़ान के उत्तर के साथ, यह बेहद असंभव है कि यह वैसे भी प्रयास के लायक होगा। लोग रेगेक्स प्रदर्शन के बारे में बहुत ज्यादा चिंता करते हैं। –

+0

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

संबंधित मुद्दे