2014-12-20 4 views
7

मैं एक अमूर्त कार्य लिख रहा हूं जो उपयोगकर्ता को एक प्रश्न पूछेगा और दिए गए नियमित अभिव्यक्ति के आधार पर उत्तर को मान्य करेगा। प्रश्न तब तक दोहराया जाता है जब तक कि उत्तर सत्यापन regexp से मेल नहीं खाता। हालांकि, मैं यह भी चाहता हूं कि क्लाइंट यह निर्दिष्ट करने में सक्षम हो कि क्या उत्तर केस-संवेदना से मेल खाना चाहिए या नहीं। तो इस तरह कुछ:मैं एक चर का उपयोग perl में regex संशोधक के रूप में कैसे करूँ?

sub ask { 
    my ($prompt, $validationRe, $caseSensitive) = @_; 
    my $modifier = ($caseSensitive) ? "" : "i"; 
    my $ans; 
    my $isValid; 

    do { 
     print $prompt; 
     $ans = <>; 
     chomp($ans); 

     # What I want to do that doesn't work: 
     # $isValid = $ans =~ /$validationRe/$modifier; 

     # What I have to do: 
     $isValid = ($caseSensitive) ? 
      ($ans =~ /$validationRe/) : 
      ($ans =~ /$validationRe/i); 

    } while (!$isValid); 

    return $ans; 
} 

उपरोक्त: क्या नियमित अभिव्यक्ति के संशोधक गतिशील रूप से निर्दिष्ट करने का कोई तरीका है?

+0

या क्या करना है जो मैं करना चाहता हूं? – livefree75

उत्तर

11

नतीजा: वहाँ किसी भी तरह से गतिशील रूप से एक नियमित अभिव्यक्ति के संशोधक निर्दिष्ट करने के लिए है?

perldoc perlre से:

"(? Adlupimsx-imsx)" "(?^Alupimsx)" एक या अधिक पैटर्न मिलान संशोधक एम्बेडेड, चालू करने की (या बंद कर दिया , यदि पहले से पैटर्न के लिए "-") या शेष संलग्न पैटर्न समूह (यदि कोई है) के लिए।

यह गतिशील पैटर्न के लिए विशेष रूप से उपयोगी है, जैसे कि को एक कॉन्फ़िगरेशन फ़ाइल से, एक तर्क से लिया गया है, या में किसी तालिका में निर्दिष्ट किया गया है। उस मामले पर विचार करें जहां कुछ पैटर्न केस-संवेदी होना चाहते हैं और कुछ नहीं करते हैं: केस-असंवेदनशील लोगों को पैटर्न के सामने "(? I)" शामिल करने के लिए केवल की आवश्यकता होती है।

जो तुम

$isValid = $ans =~ m/(?$modifier)$validationRe/; 

की तर्ज पर कुछ बस जब इस तरह से उपयोगकर्ता इनपुट को स्वीकार उचित सुरक्षा उपायों को कर लें देता है।

0

आपको eval फ़ंक्शन का उपयोग करने की आवश्यकता है। कोड के नीचे काम करेंगे:

sub ask { 
    my ($prompt, $validationRe, $caseSensitive) = @_; 
    my $modifier = ($caseSensitive) ? "" : "i"; 
    my $ans; 
    my $isValid; 

    do { 
     print $prompt; 
     $ans = <>; 
     chomp($ans); 

     # What I want to do that doesn't work: 
     # $isValid = $ans =~ /$validationRe/$modifier; 

     $isValid = eval "$ans =~ /$validationRe/$modifier"; 

     # What I have to do: 
     #$isValid = ($caseSensitive) ? 
     # ($ans =~ /$validationRe/) : 
     # ($ans =~ /$validationRe/i); 

    } while (!$isValid); 

    return $ans; 
} 
+1

हाय, इसे फ़्लैग करने से पहले, क्या कोई यह बता सकता है कि इस कोड के साथ क्या गलत है ?? 'टेस्ट: $ ans =" ​​एबीसीडीईएफ "; $ संशोधक = "मैं"; $ सत्यापनरण = "सीडी"; $ isValid = eval "$ ans = ~/$ validationRe/$ modifier"; प्रिंट $ isValid; परिणाम: 1' –

+0

यह कोड 'eval' का उपयोग इसके खतरनाक रूप में करता है। इस प्रकार कोड को तोड़ना और खतरनाक सामान भी करना बेहद आसान है (मान लीजिए कि '$ validationRe =' /; प्रिंट "के साथ क्या होता है, आपको पनड किया गया है \ n"; निकास -1; # 'या '$ ans =' die" यह कोड टूटा हुआ है! "; # '')। क्योंकि आप '$ ans' को भी विभाजित करते हैं, ऐसे बहुत कम मामले हैं जहां यह वास्तव में काम करेगा। क्या आपने इस कोड का परीक्षण भी किया है? – amon

+0

हाँ आमोन मैंने इस कोड का परीक्षण किया है। आप मेरी पहली टिप्पणी में नमूना देख सकते हैं। यदि आप उचित सत्यापन के बिना खेलने की कोशिश करते हैं तो कुछ भी हो सकता है। उपयोगकर्ता परिवर्तनीय से संशोधक को पढ़ने का एक तरीका ढूंढ रहा था, मैंने अभी एक तरीका सुझाया है। –

2

, अपने $caseSensitive पैरामीटर से छुटकारा के रूप में यह कई मामलों में बेकार हो जाएगा। इसके बजाए, उस फ़ंक्शन के उपयोगकर्ता $validationRe रेगेक्स में आवश्यक जानकारी को सीधे एन्कोड कर सकते हैं।

जब आप qr/foo/ जैसे रेगेक्स ऑब्जेक्ट बनाते हैं, तो पैटर्न उस बिंदु पर रेगेक्स इंजन के निर्देशों में संकलित होता है। यदि आप रेगेक्स ऑब्जेक्ट को स्ट्रिंग करते हैं, तो आपको एक स्ट्रिंग मिल जाएगी जो एक रेगेक्स में वापस इंटरपोलेट करने पर मूल रेगेक्स ऑब्जेक्ट के समान व्यवहार होगा। सबसे महत्वपूर्ण बात यह है कि इसका मतलब है कि रेगेक्स ऑब्जेक्ट शाब्दिक से प्रदान या छोड़ा गया सभी ध्वज संरक्षित किया जाएगा और इसे ओवरराइड नहीं किया जा सकता है! यह डिज़ाइन द्वारा है, ताकि एक रेगेक्स ऑब्जेक्ट समान व्यवहार करे, इससे कोई फर्क नहीं पड़ता कि इसका संदर्भ किस संदर्भ में किया जाता है।

यह थोड़ा सूखा है, तो चलिए एक उदाहरण का उपयोग करें। यहां एक match फ़ंक्शन है जो स्ट्रिंग्स की सूची में दो समान रेगेक्स लागू करने का प्रयास करता है। कौन सा मैच करेगा?

use strict; 
use warnings; 
use feature 'say'; 

# This sub takes a string to match on, a regex, and a case insensitive marker. 
# The regex will be recompiled to anchor at the start and end of the string. 
sub match { 
    my ($str, $re, $i) = @_; 
    return $str =~ /\A$re\z/i if $i; 
    return $str =~ /\A$re\z/; 
} 

my @words = qw/foo FOO foO/; 
my $real_regex = qr/foo/; 
my $fake_regex = 'foo'; 

for my $re ($fake_regex, $real_regex) { 
    for my $i (0, 1) { 
     for my $word (@words) { 
      my $match = 0+ match($word, $re, $i); 
      my $output = qq("$word" =~ /$re/); 
      $output .= "i" if $i; 
      say "$output\t-->" . uc($match ? "match" : "fail"); 
     } 
    } 
} 

आउटपुट:

"foo" =~ /foo/ -->MATCH 
"FOO" =~ /foo/ -->FAIL 
"foO" =~ /foo/ -->FAIL 
"foo" =~ /foo/i -->MATCH 
"FOO" =~ /foo/i -->MATCH 
"foO" =~ /foo/i -->MATCH 
"foo" =~ /(?^:foo)/  -->MATCH 
"FOO" =~ /(?^:foo)/  -->FAIL 
"foO" =~ /(?^:foo)/  -->FAIL 
"foo" =~ /(?^:foo)/i -->MATCH 
"FOO" =~ /(?^:foo)/i -->FAIL 
"foO" =~ /(?^:foo)/i -->FAIL 

सबसे पहले, हम नोटिस देना चाहिए कि regex वस्तुओं की स्ट्रिंग प्रतिनिधित्व इस अजीब (?^:...) रूप है। गैर-कैप्चरिंग समूह (?: ...) में, समूह के अंदर पैटर्न के लिए संशोधक को प्रश्न चिह्न और कोलन के बीच जोड़ा या हटाया जा सकता है, जबकि ^ झंडे के डिफ़ॉल्ट सेट को इंगित करता है।

अब जब हम नकली रेगेक्स को देखते हैं जो वास्तव में केवल एक स्ट्रिंग को इंटरपोलेट किया जाता है, तो हम देख सकते हैं कि /i ध्वज के अतिरिक्त होने के कारण एक अंतर आता है। लेकिन जब हम वास्तविक रेगेक्स ऑब्जेक्ट का उपयोग करते हैं, तो यह कुछ भी नहीं बदलता है: /i(?^: ...) झंडे को ओवरराइड नहीं कर सकता है।

यह मानना ​​शायद सबसे अच्छा है कि सभी regexes पहले से ही regex वस्तुओं हैं और इनके साथ हस्तक्षेप नहीं किया जाना चाहिए। यदि आप किसी फ़ाइल से रेगेक्स पैटर्न लोड करते हैं, तो आपको के बराबर के रूप में को लागू करने के लिए (?: ...) वाक्यविन्यास का उपयोग करने के लिए रेगेक्स की आवश्यकता होनी चाहिए)। जैसे फ़ाइल हैंडल से प्रति पंक्ति एक रेगेक्स लोड करना इस तरह दिख सकता है:

my @regexes; 
while (<$fh>) { 
    chomp; 
    push @regexes, qr/$_/; # will die here on regex syntax errors 
} 
संबंधित मुद्दे