2013-07-10 5 views
5

में रीगेक्स का उपयोग कर स्ट्रिंग के भीतर एकाधिक मैचों को प्राप्त करना this similar question पढ़ने के बाद और कई बार मेरे कोड को आजमाने के बाद, मुझे वही अवांछित आउटपुट मिल रहा है।पर्ल

मान लें कि जिस स्ट्रिंग को मैं खोज रहा हूं वह है "मैंने कल विल्मा देखा"। रेगेक्स को प्रत्येक शब्द पर कब्जा करना चाहिए, उसके बाद 'ए' और उसके वैकल्पिक 5 वर्ण या रिक्त स्थान के बाद।

$_ = "I saw wilma yesterday"; 

if (@m = /(\w+)a(.{5,})?/g){ 
    print "found " . @m . " matches\n"; 

    foreach(@m){ 
     print "\t\"$_\"\n"; 
    } 
} 

हालांकि, मैं निम्नलिखित उत्पादन हो रही है पर रखा:

कोड मैंने लिखा निम्नलिखित है

found 2 matches 
    "s" 
    "w wilma yesterday" 

जब मैं मिलने की उम्मीद के बाद एक:

found 3 matches: 
    "saw wil" 
    "wilma yest" 
    "yesterday" 

जब तक मुझे पता चला कि @m के अंदर वापसी मूल्यथेऔर $2, जैसा कि आप देख सकते हैं।

अब, /g ध्वज चालू है, और मुझे नहीं लगता कि समस्या रेगेक्स के बारे में है, मैं वांछित आउटपुट कैसे प्राप्त कर सकता हूं?

+0

मुझे समझ में नहीं आता कि आपके अपेक्षित नतीजे में 'दिन' क्यों है और 'कल' नहीं? –

+0

ठीक है, आप सही हैं। बस संपादित – none

+0

ठीक है, मेरे पास आपके लिए एक पैटर्न है। –

उत्तर

2

आप इस पैटर्न है कि ओवरलैप परिणाम की अनुमति देता है की कोशिश कर सकते हैं:

(?=\b(\w+a.{1,5})) 

या

(?=(?i)\b([a-z]+a.{0,5})) 

उदाहरण:

use strict; 
my $str = "I saw wilma yesterday"; 
my @matches = ($str =~ /(?=\b([a-z]+a.{0,5}))/gi); 
print join("\n", @matches),"\n"; 

अधिक स्पष्टीकरण:

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

इस व्यवहार के एक और उदाहरण के लिए, परिणाम देखने के लिए आप शब्द सीमा (\b) के बिना उदाहरण कोड का प्रयास कर सकते हैं।

+0

मैंने इसका परीक्षण किया और यह काम किया। बहुत बढ़िया। 'जबकि (एम/(? = \ बी (\ डब्ल्यू + ए। {1,5}))/जी) {प्रिंट" $ 1 \ n "; } ' –

+0

हाँ, यह ठीक से काम करता है। लेकिन "? =" लुकहेड विकल्प नहीं था? यह जरूरी क्यों है? – none

+0

@ नहीं: लुकहेड ओवरलैप्ड मैचों की अनुमति देता है, तो आप एक शॉट में ओवरलैप किए गए परिणाम (जैसे 'देखा wil' और' wilma yest') हो सकते हैं। उदाहरण देखें। –

1

सबसे पहले आप, अभिव्यक्ति के अंदर सब कुछ पर कब्जा करना चाहते हैं यानी .:

/(\w+a(?:.{5,})?)/ 

इसके बाद आप अतीत जहां पिछले अभिव्यक्ति की पहली चरित्र का मिलान नहीं हुआ एक चरित्र से अपनी खोज शुरू करना चाहते हैं।

pos() फ़ंक्शन आपको यह निर्दिष्ट करने की अनुमति देता है कि /g रेगेक्स इसकी खोज कहां से शुरू करता है।

1
$s = "I saw wilma yesterday";  
while ($s =~ /(\w+a(.{0,5}))/g){ 
    print "\t\"$1\"\n"; 
    pos($s) = pos($s) - length($2); 
} 

आप देता है:

"saw wil" 
"wilma yest" 
"yesterday" 

लेकिन मैं नहीं जानता कि क्यों तुम day और नहीं yesterday मिलना चाहिए।