2011-09-10 12 views
10

क्या अनंत लूप प्राप्त किए बिना ऐसा करने का कोई तरीका है?असीमित जबकि-लूप में perl

while((my $var) = $string =~ /regexline(.+?)end/g) { 
    print $var; 
} 

यह एक अनंत लूप में परिणाम है, शायद इसलिए है, जबकि अंदर एक regex से सीधे एक वर के बताए "सही" हर बार रिटर्न?

मैं जानता हूँ कि मैं यह कर सकता:

while($string =~ /regexline(.+?)end/g) { 
    my $var = $1;  
    print $var; 
} 

लेकिन मैं मैं एक पंक्ति को बचा सकता है उम्मीद कर रहा था। क्या कोई रेगेक्स संशोधक है जिसका मैं उपयोग कर सकता हूं या ऐसा कुछ कर सकता हूं?

(इसके अलावा, वास्तव में कहा जाता है इस अंकन/चाल क्या है, अगर मैं इसे खोज करना चाहते हैं:

(my $var) = $string =~ /regex/; 

धन्यवाद !!

उत्तर

8

वहाँ एक अनंत लूप प्राप्त किए बिना ऐसा करने के लिए कोई तरीका है?

हां। थोड़ी देर के() पाश के बजाय एक foreach (का प्रयोग करें):

foreach my $var ($string =~ /regexline(.+?)end/g) { 

इस अंकन/चाल वास्तव में कहा जाता है, अगर मैं खोज करने के लिए के लिए यह

यह में एक मैच भी कहा जाता है चाहता हूँ क्या सूची संदर्भ। यह "perldoc perlop" में वर्णित है:

जी संशोधक वैश्विक पैटर्न मिलान निर्दिष्ट करता है - यानी, स्ट्रिंग के भीतर जितनी बार संभव हो सके मिलान करता है। यह कैसे व्यवहार करता है संदर्भ पर निर्भर करता है। सूची संदर्भ में ...

+2

चेतावनी दी जानी चाहिए कि 'foreach' पूरे परिणाम को स्मृति में लोड करता है जैसे कि' while' करता है। – hhaamu

10

अदिश संदर्भ में, /g संशोधक के साथ एक नियमित अभिव्यक्ति होगा पुनरावर्तक की तरह काम करते है और एक झूठी मान जब वहाँ कोई अधिक मैच हैं:

print "$1\n" while "abacadae" =~ /(a\w)/g;  # produces "ab","ac","ad","ae" 

while अभिव्यक्ति, वाई के अंदर काम के साथ कहां सूची संदर्भ में अपनी नियमित अभिव्यक्ति का मूल्यांकन कर रहे हैं। अब आपकी नियमित अभिव्यक्ति अब एक इटरेटर की तरह कार्य नहीं करती है, यह सिर्फ मैचों की सूची देता है। यदि सूची खाली नहीं है, यह एक सही मूल्य का आकलन करती:

print "$1\n" while() = "abacadae" =~ /(a\w)/g; # infinite "ae" 

इसे ठीक करने के लिए आपको जबकि बयान से बाहर काम लेने के लिए और पाश के अंदर काम करने के लिए निर्मित $1 चर का उपयोग कर सकते हैं?

while ($string =~ /regexline(.+?)end/g) { 
    my $var = $1; 
    print $var; 
} 
0

कम कोड के साथ ऐसा करने के कई तरीके हैं।

मान लें कि आपकी फ़ाइल lines.txt कहा जाता है मान लीजिए:

regexlineabcdefend 
regexlineghijkend 
regexlinelmnopend 
regexlineqrstuend 
This line does not match 
Neither does this 
regexlinevwxyzend 

और आप टुकड़े कि आपके रेगुलर एक्सप्रेशन से मेल निकालना चाहते हैं, वह है, "regexline" और "अंत" के बीच की रेखा का हिस्सा। एक सीधा पर्ल स्क्रिप्ट है:

while (<STDIN>) { 
    print "$1\n" if $_ =~ /regexline(.+?)end/ 
} 

इस

$ perl match.pl < lines.txt 

की तरह चलाते हैं आप

मिल
abcdef 
ghijk 
lmnop 
qrstu 
vwxyz 

तुम भी कमांडलाइन पर पूरी बात कर सकते हैं!

$ पर्ल -nle 'प्रिंट $ 1 अगर $ _ = ~ /regexline(.+?)end/' < lines.txt abcdef ghijk lmnop qrstu vwxyz

जहां तक ​​आपके दूसरे प्रश्न के रूप में चला जाता है, मुझे यकीन नहीं है कि उस चाल के लिए एक विशेष पर्ल नाम है।

0

मुझे लगता है कि आपकी सबसे अच्छी शर्त लूप के भीतर $ स्ट्रिंग को प्रतिस्थापित करना है ...इसलिए:

while((my $var) = $string =~ /regexline(.+?)end/g) { 
    $string =~ s/$var//; 
    print $var . "\n"; 
} 
+0

मेरा सुझाव है कि आप उस कोड को चलाने का प्रयास करें; इसमें वाक्यविन्यास त्रुटियां हैं। 'var $ प्रिंट करें। "\ n"; 'ठीक है, लेकिन' प्रिंट "$ var \ n"; 'क्लीनर है। और आपको '$ string' पर एक और प्रतिस्थापन करने की आवश्यकता नहीं है; आप प्रारंभिक regexp में नया मान कैप्चर कर सकते हैं और उसे '$ string' असाइन कर सकते हैं। –

8

Perl regular expressions tutorial का कहना है:

अदिश संदर्भ में, एक स्ट्रिंग के खिलाफ लगातार आमंत्रण // मैच मैच के लिए से छ कूद होगा, स्ट्रिंग में स्थिति का ट्रैक रखने के रूप में यह साथ चला जाता है ।

लेकिन:

सूची संदर्भ में, // जी का मिलान नहीं हुआ समूहों की एक सूची देता है, या अगर कोई समूहों, पूरे regexp को मिलान की सूची है।

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

तो आप लूप स्थिति में सूची संदर्भ असाइनमेंट का उपयोग नहीं कर सकते हैं, क्योंकि यह वही नहीं करता है जो आप चाहते हैं।

आप सूची संदर्भ का उपयोग कर पर जोर देते हैं, तो आप के बजाय ऐसा कर सकता है:

foreach my $var ($string =~ /regexline(.+?)end/g) { 
    print $var; 
} 
0

मैं तुम्हें इस प्रिंट के साथ क्या करना चाहते हैं क्या पता नहीं है, लेकिन यह यह करने का एक अच्छा तरीका है:

say for $string =~ /regex(.+?)end/g; 

को The (foreach के रूप में ही) रेगेक्स मैच को कैप्चर समूहों की सूची में फैलाता है, और उन्हें प्रिंट करता है। इस तरह काम करता है:

@matches = $string =~ /regex(.+?)end/g; 
say for (@matches); 

while कुछ अलग है। चूंकि यह एक स्केलर संदर्भ का उपयोग करता है, यह कैप्चर समूहों को स्मृति में लोड नहीं करता है।

say $1 while $string =~ /regex(.+?)end/g; 

यह अपने मूल कोड की तरह कुछ करना होगा छोड़कर हम एक संक्रमण चर $var उपयोग करने के लिए की जरूरत नहीं है, हम बस इसे तुरंत मुद्रित करें।

1

यह एक परिस्थिति है जहां आप व्यवहार को बदले बिना वैश्विक युद्धों का उपयोग नहीं कर सकते हैं।

while ($string =~ /regexline(.+?)end/g) { 
    my $var = $1; 
    ... 
} 

यदि आपके पास केवल एक कैप्चर है, तो आप एक ही समय में सभी मैचों को ढूंढकर वैश्विक युद्धों का उपयोग करने से बच सकते हैं।

for my $var ($string =~ /regexline(.+?)end/g) { 
    ... 
} 

दूसरे संस्करण की अतिरिक्त लागत आमतौर पर नगण्य है।