2012-04-27 16 views
7

में * संशोधक के साथ नकारात्मक अग्रदर्शी अभिकथन मेरे पास है (मैं होने के लिए विश्वास) नकारात्मक अग्रदर्शी अभिकथन<@> *(?!QQQ) है कि मैं अगर परीक्षण किया स्ट्रिंग एक <@> रिक्त स्थान (शून्य सहित) के किसी भी संख्या के द्वारा पीछा किया है मिलान की उम्मीद और फिर QQQ के बाद।पर्ल

फिर भी, यदि परीक्षण स्ट्रिंग <@> QQQ नियमित अभिव्यक्ति मिलान है।

मैं यह देखने में असफल रहा कि यह मामला क्यों है और इस मामले पर किसी भी मदद की सराहना करेगा।

यहाँ एक परीक्षण स्क्रिप्ट

use warnings; 
use strict; 

my @strings = ('something <@> QQQ', 
       'something <@> RRR', 
       'something <@>QQQ' , 
       'something <@>RRR'); 


print "$_\n" for map {$_ . " --> " . rep($_) } (@strings); 



sub rep { 

    my $string = shift; 

    $string =~ s,<@> *(?!QQQ),at w/o ,; 
    $string =~ s,<@> *QQQ,at w/ QQQ,; 

    return $string; 
} 

है यह प्रिंट

something <@> QQQ --> something at w/o QQQ 
something <@> RRR --> something at w/o RRR 
something <@>QQQ --> something at w/ QQQ 
something <@>RRR --> something at w/o RRR 

और मैं पहली पंक्ति something <@> QQQ --> something at w/ QQQ होने की उम्मीद है चाहते हैं।

उत्तर

10

यह मेल खाता है क्योंकि शून्य "किसी भी संख्या" में शामिल है। तो किसी भी स्थान के बाद कोई स्थान नहीं, "किसी भी संख्या के रिक्त स्थान" के बाद मेल नहीं खाता है।

आपको एक और दिखने वाला दावा जोड़ना चाहिए कि आपकी जगहों के बाद पहली चीज स्वयं एक जगह नहीं है। इस (untested) का प्रयास करें:

<@> *(?!QQQ)(?!) 

ईटीए साइड नोट: बदलते + परिमाणक मदद की है | वहाँ केवल जब ठीक एक स्थान; सामान्य मामले में, रेगेक्स हमेशा एक कम जगह ले सकता है और इसलिए सफल होता है। Regexes मिलान करना चाहते हैं, और किसी भी तरह से ऐसा करने के लिए पीछे की तरफ झुकना होगा। अन्य सभी विचार (बाएं, सबसे लंबे, आदि) एक पिछली सीट लें - यदि यह एक से अधिक तरीकों से मेल खा सकता है, तो वे निर्धारित करते हैं कि किस तरह से चुना गया है। लेकिन मिलान हमेशा मिलान नहीं जीतता है। तुम्हारा यहाँ की

+3

'(? = \ एस)' होना चाहिए (? = [^]) '(यदि अगला वर्ण एक टैब है)। असल में, यह '(?!)' होना चाहिए (यदि यह स्ट्रिंग का अंत है)। – ikegami

+0

पकड़ और संपादित करने के लिए धन्यवाद, @ikegami। '*' –

7
$string =~ s,<@> *(?!QQQ),at w/o ,; 
$string =~ s,<@> *QQQ,at w/ QQQ,; 

एक समस्या यह है कि आप दो regexes अलग से देख रहे हैं है। आप पहले QQQ के बिना स्ट्रिंग को प्रतिस्थापित करने के लिए कहते हैं, और उसके बाद स्ट्रिंग को QQQ के साथ प्रतिस्थापित करने के लिए कहते हैं। यह वास्तव में एक ही चीज़ में दो बार एक ही चीज़ की जांच कर रहा है। उदाहरण के लिए: if (X==0) { ... } elsif (X!=0) { ... }। दूसरे शब्दों में, कोड बेहतर लिखा जा सकता है:

unless ($string =~ s,<@> *QQQ,at w/ QQQ,) { 
    $string =~ s,<@> *,at w/o,; 
} 

तुम हमेशा * परिमाणक के साथ सावधान रहना होगा। चूंकि यह शून्य या अधिक बार मेल खाता है, यह खाली स्ट्रिंग से भी मेल खाता है, जिसका मूल रूप से अर्थ है: यह किसी भी स्ट्रिंग में किसी भी स्थान से मेल खा सकता है।

एक नकारात्मक दिखने वाले दावे की एक समान गुणवत्ता है, इस अर्थ में कि इसे केवल एक ही चीज मिलनी चाहिए जो मिलान करने के लिए अलग हो। इस मामले में, यह "<@> " भाग <@> + कोई स्थान + स्थान से मेल नहीं खाता है, जहां अंतरिक्ष निश्चित रूप से "नहीं" QQQ है। आप यहाँ एक तार्किक बाधा पर कम या ज्यादा हैं, क्योंकि * क्वांटिफायर और नकारात्मक एक-दूसरे के सामने एक-दूसरे के सामने है।

मुझे विश्वास है कि इसे हल करने का सही तरीका रेगेक्स को अलग करना है, जैसा मैंने ऊपर दिखाया था। दोनों regexes निष्पादित होने की संभावना की अनुमति देने में कोई समझ नहीं है।

हालांकि, सैद्धांतिक उद्देश्यों के लिए, एक कामकाजी रेगेक्स जो किसी भी रिक्त स्थान, और दोनों को नकारात्मक दिखने की अनुमति देता है, उन्हें एंकर किया जाना चाहिए। Mark Reed की तरह बहुत कुछ दिखाया गया है। यह सबसे आसान हो सकता है।

<@>(?! *QQQ)  # Add the spaces to the look-ahead 

अंतर यह है कि अब रिक्त स्थान और क्यू एक दूसरे के लिए लगी हुई हैं, जबकि इससे पहले कि वे अलग से मिल सकें। घर * परिमाणक के बिंदु ड्राइव करने के लिए, और भी अतिरिक्त रिक्त स्थान को हटाने की एक छोटी सी समस्या को हल, आप का उपयोग कर सकते हैं:

<@> *(?! *QQQ) 

इसका कारण यह है परिमाणक के या तो खाली स्ट्रिंग मिलान कर सकते हैं काम करेंगे। सैद्धांतिक रूप से, आप इनमें से जितना चाहें उतना जोड़ सकते हैं, और इससे कोई फर्क नहीं पड़ता (प्रदर्शन में छोड़कर): / * * * * * * */ कार्यात्मक रूप से / */ के बराबर है। यहां अंतर यह है कि क्यूएस के साथ संयुक्त स्थान मौजूद नहीं हो सकते हैं।

+0

+1 '+ 'के जोड़ को जोड़ता है, लेकिन मैं यह नहीं बता सकता कि क्यों। – flies

4

रेगेक्स इंजन तब तक बैकट्रैक करेगा जब तक कि यह एक मैच न मिले, या एक मैच ढूंढना असंभव हो। इस मामले में, यह निम्नलिखित मैच मिला:

      +--------------- Matches "<@>". 
         | +----------- Matches "" (empty string). 
         | |  +--- Doesn't match " QQQ". 
         | |  | 
         --- ---- --- 
'something <@> QQQ' =~ /<@> [ ]* (?!QQQ)/x 

आपको बस इतना करना है कि चीजों को चारों ओर घुमाएं। बदलें

/<@>[ ]*(?!QQQ)/ 

/<@>(?![ ]*QQQ)/ 

साथ

या आप यह इतना regex केवल सभी रिक्त स्थान की पूर्ति करेंगे कर सकते हैं:

/<@>[ ]*+(?!QQQ)/ 
/<@>[ ]*(?![ ]|QQQ)/ 
/<@>[ ]*(?![ ])(?!QQQ)/ 

पुनश्च — रिक्त स्थान को देखने के लिए मुश्किल है, इसलिए मैं [ ] का उपयोग उन्हें और अधिक दृश्यमान बनाने के लिए। यह वैसे भी अनुकूलित हो जाता है।

+0

के विस्तृत स्पष्टीकरण के लिए – flies

+0

प्रतीक्षा करें, मुझे लगता है कि मुझे यह मिल गया है। '[] * + 'यह सुनिश्चित करता है कि सभी उपलब्ध रिक्त स्थानों को पकड़ लिया जाए, भले ही यह मैच तोड़ता है, जबकि' [] *' मैच को तोड़ने के बिना जितना हो सके उतना पकड़ लेगा। – flies

+0

@flies, क्योंकि '" "= ~/* + /' केवल '' 'से मेल खा सकता है। यह '' '' से मिलान करने के लिए बैकट्रैक नहीं होगा, इसलिए अब यह मैच '/ * /' नहीं मिल सकता है। – ikegami