2011-01-18 3 views
8

(नोट: शीर्षक स्पष्ट करने के लिए प्रतीत नहीं होता है - अगर किसी को इस मैं इसके लिए सभी हूँ अलग तरीके से व्यक्त कर सकते हैं!)एकल वर्ण मिलान के लिए वैकल्पिक या वर्ण वर्ग का उपयोग करना?

इस regex को देखते हुए: (.*_e\.txt) है, जो कुछ फ़ाइल नाम से मेल खाता है, मैं कुछ अन्य एकल वर्ण जोड़ने की जरूरत e के अतिरिक्त प्रत्यय। क्या मुझे एक चरित्र वर्ग चुनना चाहिए या क्या मुझे इसके लिए एक विकल्प का उपयोग करना चाहिए? (या यह वास्तव में कोई फर्क पड़ता है ??)

यही है, जो निम्नलिखित दो की "बेहतर" लगता है, और यही कारण है:

क) (.*(e|f|x)\.txt), या

ख) (.*[efx]\.txt)

+1

आप कठिन __any__ प्रदर्शन को मापने के आगे बढ़ा दिया जाएगा दोनों के बीच अंतर। चिंता करना बंद करो और केवल स्पष्ट का उपयोग करें। – bobbogo

+1

@bobbogo: ध्यान दें कि सवाल विशेष रूप से प्रदर्शन के बारे में नहीं था, लेकिन बस "बेहतर" + क्यों। –

+0

@ मार्टिन: मैं पूरी तरह से सहमत हूं। साफ़ कोड यहां प्राथमिकता है। – bobbogo

उत्तर

16

उपयोग [efx] - यह बिल्कुल सही चरित्र वर्गों के लिए डिज़ाइन किया गया है: शामिल वर्णों में से किसी एक से मिलान करने के लिए। इसलिए यह भी सबसे अधिक पढ़ने योग्य और सबसे छोटा समाधान है।

मुझे नहीं पता कि यह तेज़ है, लेकिन अगर यह नहीं था तो मुझे बहुत आश्चर्य होगा। यह निश्चित रूप से धीमा नहीं होगा।

मेरे तर्क (अब तक लिखी होने एक regex इंजन के बिना, तो यह शुद्ध अनुमान है):

regex टोकन [abc] regex इंजन के एक ही चरण में लागू किया जाएगा: "अगले वर्ण a से एक है , b, या c? "

(a|b|c) तथापि

  • करने के लिए regex इंजन बताता है उलटे पांव लौटने के लिए स्ट्रिंग में वर्तमान स्थिति याद है, यदि आवश्यक हो तो
  • जांच अगर यह a मिलान करने के लिए संभव है। यदि हां, तो सफलता। यदि नहीं:
  • जांचें कि b से मेल खाना संभव है या नहीं। यदि हां, तो सफलता। यदि नहीं:
  • जांचें कि c से मिलान करना संभव है या नहीं। यदि हां, तो सफलता। यदि नहीं:
  • छोड़ दें।
1

एक ही चरित्र के साथ, इसमें इतना अंतर नहीं होगा कि इससे कोई फर्क नहीं पड़ता। (जब तक आप संचालन के बहुत सारे काम नहीं कर रहे हैं)

हालांकि, पठनीयता (और थोड़ा प्रदर्शन वृद्धि) के लिए आपको चरित्र वर्ग विधि का उपयोग करना चाहिए।

थोड़ी और जानकारी के लिए - एक राउंड ब्रैकेट खोलने के लिए ( पर्ल को उस वर्तमान स्थिति के लिए बैकट्रैकिंग शुरू करने का कारण बनता है, क्योंकि आपके पास आगे जाने के लिए और अधिक मिलान नहीं हैं, आपको वास्तव में अपने regex की आवश्यकता नहीं है। एक चरित्र वर्ग ऐसा नहीं करेगा।

+1

आप '(?> ...) ', स्वतंत्र उपसमूह का उपयोग कर समूह में बैकट्रैकिंग पर कुछ नियंत्रण रख सकते हैं। एक बार कुछ संभावनाओं पर फैसला लेने के बाद समूह को फिर से संशोधित नहीं किया जाएगा। हालांकि, इसका उपयोग करना थोड़ा मुश्किल है। – tchrist

+0

@ क्रिसमस: हर बार जब आप उपसमूह को कैप्चर नहीं करना चाहते हैं तो बस इतना सरल '(?: ...)' का उपयोग कर रहा है। –

11

यहाँ एक बेंचमार्क है:

अपडेट tchrist टिप्पणी के अनुसार, अंतर और अधिक महत्वपूर्ण है

#!/usr/bin/perl 
use strict; 
use warnings; 
use 5.10.1; 
use Benchmark qw(:all); 

my @l; 
foreach(qw/b c d f g h j k l m n ñ p q r s t v w x z B C D F G H J K L M N ñ P Q R S T V W X Z/) { 
    push @l, "abc$_.txt"; 
} 

my $re1 = qr/^(.*(b|c|d|f|g|h|j|k|l|m|n|ñ|p|q|r|s|t|v|w|x|z)\.txt)$/; 
my $re2 = qr/^(.*[bcdfghjklmnñpqrstvwxz]\.txt)$/; 
my $cpt; 

my $count = -3; 
my $r = cmpthese($count, { 
    'alternation' => sub { 
     for(@l) { 
      $cpt++ if $_ =~ $re1; 
     } 
    }, 
    'class' => sub { 
     for(@l) { 
      $cpt++ if $_ =~ $re2; 
     } 
    } 
}); 

परिणाम:

   Rate alternation  class 
alternation 2855/s   --  -50% 
class  5677/s   99%   -- 
+2

यह एक दिलचस्प है - और, मुझे लगता है, उपयोगी - चित्रण। हालांकि इसमें बहुत कुछ नहीं है। यदि आप इनपुट डेटा बदलते हैं, तो आप अलग-अलग प्रदर्शन प्राप्त करेंगे, जैसा कि आप भी करेंगे, यदि आप पैटर्न बदलते हैं। उदाहरण के लिए, '[bcdfghjklmnñpqrstvwxz] 'बनाम' (बी | सी | डी | एफ | जी | एच | जे | के | एल | एम | एन | एन | पी | क्यू | आर | एस | टी | वी | डब्ल्यू | एक्स | z) 'स्पेनिश व्यंजनों के लिए बहुत लंबा है, और संभवतः विभिन्न प्रदर्शन विशेषताओं को दिखाना चाहिए। – tchrist

+0

मुझे लगता है कि आपको 'utf8 का उपयोग करें;' प्रज्ञा का उपयोग करना चाहिए क्योंकि आपका '$ re1' और' $ re2' समान नहीं है ;-) –

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