2009-06-12 7 views
8

मैं अपने लिपियों में से एक पर पर्ल :: समालोचक भाग गया, और यह संदेश मिला:क्या पर्ल रेगेक्स को/x के साथ लिखने का कोई बेहतर तरीका है ताकि कोड अभी भी पढ़ना आसान हो?

Regular expression without "/x" flag at line 21, column 26. See page 236 of PBP. 

मैं नीति जानकारी here देखा और मैं समझता हूँ कि विस्तारित मोड में नियमित अभिव्यक्ति लिख जो कोई देख रहा है में मदद मिलेगी कोड पर

हालांकि, मैं अपने कोड को/x ध्वज का उपयोग करने के लिए कैसे परिवर्तित करना है, इस तरह अटक गया हूं।

CPAN उदाहरण:

# Match a single-quoted string efficiently... 

m{'[^\\']*(?:\\.[^\\']*)*'}; #Huh? 

# Same thing with extended format... 

m{ 
    '   # an opening single quote 
    [^\\']  # any non-special chars (i.e. not backslash or single quote) 
    (?:   # then all of... 
     \\ . # any explicitly backslashed char 
     [^\\']* # followed by an non-special chars 
    )*   # ...repeated zero or more times 
    '   # a closing single quote 
}x; 

यह समझ में आता है अगर आप केवल regex को देखो।

मेरे कोड:

if ($line =~ /^\s*package\s+(\S+);/) { 

मैं बिल्कुल यकीन है कि कैसे एक के अंदर एक विस्तारित regex का उपयोग करने के लिए अगर बयान नहीं कर रहा हूँ। मैं इसे इस तरह लिख सकता हूं:

if (
     $line =~/
     ^\s* # starting with zero or more spaces 
     package 
     \s+  # at least one space 
     (\S+) # capture any non-space characters 
     ;  # ending in a semi-colon 
     /x 
    ) 
    { 

और यह काम करता है, लेकिन मुझे लगता है कि मूल से पढ़ने के लिए यह लगभग कठिन है। क्या यह लिखने के लिए एक बेहतर तरीका (या एक सर्वोत्तम अभ्यास तरीका) है? मुझे लगता है कि मैं qr // का उपयोग कर एक चर बना सकता हूं।

मैं वास्तव में इस विशिष्ट रेगेक्स को फिर से लिखने पर सलाह नहीं ढूंढ रहा हूं (हालांकि अगर मैं इसे सुधार सकता हूं, तो मैं सलाह लेता हूं) - मैं सलाह देता हूं कि एक रेगेक्स को कैसे अंदर विस्तारित किया जाए अगर बयान।

मुझे पता है पर्ल :: आलोचक सिर्फ एक दिशानिर्देश है, लेकिन इसका पालन करना अच्छा होगा।

अग्रिम धन्यवाद!

संपादित करें: तो कुछ जवाब प्राप्त करने के बाद, यह मेरे लिए स्पष्ट हो गया कि टिप्पणी के साथ एक regex बहु लाइन बनाने हमेशा जरूरी नहीं है। जो लोग मूल रेगेक्स को समझते हैं उन्हें यह समझने में सक्षम होना चाहिए कि मेरा उदाहरण क्या कर रहा था - मैंने जो टिप्पणियां जोड़ीं वह शायद थोड़ी अनावश्यक और वर्बोज़ थीं। मुझे विस्तारित रेगेक्स ध्वज का उपयोग करने का विचार पसंद है, लेकिन फिर भी रेगेक्स में रिक्त स्थान को रेगेक्स के प्रत्येक भाग को थोड़ा और स्पष्ट करने के लिए एम्बेड करना पसंद है। सभी इनपुट के लिए धन्यवाद!

उत्तर

11

ठीक है, मुझे नहीं लगता कि आपको इस पर लंबवत स्क्रीन अचल संपत्ति बर्बाद करनी चाहिए। दूसरी ओर, अगर मैं कई लाइनों पर इस पैटर्न लिखने के लिए थे, मैं ब्रेसिज़ इस्तेमाल किया है | और पैटर्न इंडेंट:

if ($line =~ m{ 
     \A \s* 
     package 
     \s+ 
     (\S+) 
     \s* ; 
    }x 
) { 

IMHO, निम्न संस्करण बिल्कुल ठीक है:

if ($line =~ m{ \A \s* package \s+ (\S+) \s* ; }x ) { 

में m//x का लाभ प्राप्त करने की शर्तें।

टिप्पणियां इस मामले में पूरी तरह से अनावश्यक हैं क्योंकि आप कुछ भी मुश्किल नहीं कर रहे हैं। मैंने अर्ध-कोलन से पहले \s* जोड़ा क्योंकि कभी-कभी लोग पैकेज नाम से अलग अर्द्ध-कोलन सेट करते हैं और जो आपके मैच को फेंकना नहीं चाहिए।

+0

मुझे करना था "\ A" का अर्थ देखने के लिए http://www.perl.com/doc/manual/html/pod/perlre.html पर जाएं। क्या यह "^" के बजाय पसंदीदा तरीका है? – BrianH

+2

मुझे लगता है कि मैंने पहले एक सिंगल लाइन रेगेक्स में व्हाइटस्पेस जोड़ने का विचार नहीं किया था। मैं हमेशा "/ x" ध्वज के बारे में सोचता हूं, केवल एक बहु-रेखा ध्वज के रूप में, लेकिन मुझे वास्तव में उपरोक्त आपका उदाहरण पसंद है। – BrianH

+2

@ ब्रायनएच: नहीं, वास्तव में नहीं। यदि आप/m का उपयोग करते हैं, और जब आप उपयोग करते हैं, तो यह केवल एक फर्क पड़ता है, आप आमतौर पर ^, नहीं \ A चाहते हैं। दूसरी तरफ $ अक्सर उपयोग किया जाता है जहां लोग वास्तव में \ z। – ysth

8

ऐसी अतिरिक्त जानकारी द्वारा जोड़े गए मूल्य के रूप में आपका कॉल बहुत अधिक है।

कभी-कभी आप सही होते हैं, यह कुछ भी नहीं जोड़ता है कि क्या हो रहा है और कोड को गन्दा लग रहा है, लेकिन जटिल नियमित अभिव्यक्तियों के लिए, x ध्वज एक वरदान हो सकता है।

दरअसल, अतिरिक्त जानकारी के अतिरिक्त मूल्य के संबंध में यह "कॉल करना" काफी मुश्किल हो सकता है।

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

संपादित करें: कुछ तरीकों से, सीपीएएन उदाहरण वास्तव में उपयोगी नहीं है। एक जटिल regexp का वर्णन करने के लिए टिप्पणियों को जोड़ने के लिए एक्स ध्वज का उपयोग करते समय, मैं उन घटकों का वर्णन करता हूं जो regexp खुद को regexp "बिट्स" का वर्णन करने के बजाय मिलान करने की कोशिश कर रहा है।

  • पहले घटक ब्रिटेन पोस्टकोड की (क्षेत्र और जिले), या
  • अंतरराष्ट्रीय ब्रिटेन के लिए क्षेत्र कोड, या
  • किसी भी ब्रिटेन मोबाइल फ़ोन नंबर: उदाहरण के लिए, मैं जैसी चीजों के बारे में था ।

जो मुझे और अधिक से अधिक

  • एक या दो पत्र बताता है, एक नंबर, वैकल्पिक रूप से एक पत्र के बाद के बाद, या
  • दो चार अंक एक साथ, या
  • एक शून्य है, का पालन किया चार दशमलव अंकों, एक डैश और फिर छह दशमलव अंक से।

मेरी भावना इस मामले में regexp टिप्पणियां छोड़ना होगा। तुम्हारी आंत महसूस सही है!

+1

रेगेक्स का वर्णन करने के बारे में बहुत अच्छा संपादन। मैं रेगेक्स क्या कर रहा है (जैसे "किसी भी गैर-स्पेस कैरेक्टर को कैप्चर करें") का वर्णन करने के जाल में पड़ता हूं, जब शायद "पैकेज नाम कैप्चर" जैसे कुछ और स्पष्ट हो। अगर मैं कर सकता तो मैं आपकी पोस्ट फिर से +1 करूंगा! – BrianH

+0

धन्यवाद @BrianH। सी "I ++;" की एक पंक्ति के ऊपर "# add 1 to i" जैसी टिप्पणियों के साथ लगी हुई कोड को ढूंढना बहुत अच्छा दर्द है। ;-) –

1

ऐसा लगता है कि इस स्थिति में एक मल्टीलाइन को लगातार इंडेंट करने का सवाल है ... जिसके लिए बहुत सारे उत्तर हैं। वास्तव में क्या मायने रखता है स्थिरता है। यदि आप पर्ल्टिडी या किसी अन्य फॉर्मेटर का उपयोग करते हैं, तो इसके साथ-साथ आपके कॉन्फ़िगरेशन के साथ सुसंगत रहें। हालांकि, मैं डिलीमीटर से रेगेक्स एक स्तर की सामग्री को इंडेंट कर दूंगा।

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

+0

मैंने "*" कहां छोड़ा? मेरे पास इस स्क्रिप्ट के लिए एक छोटा परीक्षण सूट है, हां। स्क्रिप्ट सिर्फ स्थापित पर्ल मॉड्यूल के लिए मेरे सिस्टम को खोजने के लिए है, इसलिए यदि यह टूट जाता है तो यह बहुत महत्वपूर्ण नहीं है - लेकिन मौजूदा कोड को साफ करने के बारे में बताया गया है। – BrianH

+0

ओह - आप सीपीएएन उदाहरण के बारे में बात कर रहे थे जिसमें गायब "*" है। मैंने इसे सीधे http://search.cpan.org/~elliotjs/Perl-Critic-1.098/lib/Perl/Critic/Policy/RegularExpressions/RequireExtendedFormatting.pm से लिया - यह मेरा कोड नहीं है। लेकिन यह आपके बिंदु को चित्रित करता है। – BrianH

+0

@BrianH: धन्यवाद, निश्चित – ysth

11

कोई टिप्पणी नहीं लिखती जो कहती है कि कोड क्या कहता है। टिप्पणियां आपको बताती हैं कि कोड कहता है कि यह क्या कहता है। टिप्पणी यह ​​बहुत मुश्किल है यह देखने के लिए कि क्या हो रहा है बिना इस कुरूपता पर एक नजर डालें,, लेकिन टिप्पणी यह ​​स्पष्ट क्या मिलान किया जा करने की कोशिश कर रहा है:

require 5.010; 
my $sep   = qr{ [/.-] }x;    #allowed separators  
my $any_century = qr/ 1[6-9] | [2-9][0-9] /x; #match the century 
my $any_decade = qr/ [0-9]{2} /x;   #match any decade or 2 digit year 
my $any_year = qr/ $any_century? $any_decade /x; #match a 2 or 4 digit year 

#match the 1st through 28th for any month of any year 
my $start_of_month = qr/ 
    (?:       #match 
     0?[1-9] |    #Jan - Sep or 
     1[0-2]     #Oct - Dec 
    ) 
    ($sep)      #the separator 
    (?: 
     0?[1-9] |    # 1st - 9th or 
     1[0-9] |    #10th - 19th or 
     2[0-8]     #20th - 28th 
    ) 
    \g{-1}      #and the separator again 
/x; 

#match 28th - 31st for any month but Feb for any year 
my $end_of_month = qr/ 
    (?: 
     (?: 0?[13578] | 1[02]) #match Jan, Mar, May, Jul, Aug, Oct, Dec 
     ($sep)     #the separator 
     31      #the 31st 
     \g{-1}     #and the separator again 
     |      #or 
     (?: 0?[13-9] | 1[0-2]) #match all months but Feb 
     ($sep)     #the separator 
     (?:29|30)    #the 29th or the 30th 
     \g{-1}     #and the separator again 
    ) 
/x; 

#match any non-leap year date and the first part of Feb in leap years 
my $non_leap_year = qr/ (?: $start_of_month | $end_of_month) $any_year/x; 

#match 29th of Feb in leap years 
#BUG: 00 is treated as a non leap year 
#even though 2000, 2400, etc are leap years 
my $feb_in_leap = qr/ 
    0?2       #match Feb 
    ($sep)      #the separtor 
    29       #the 29th 
    \g{-1}      #the separator again 
    (?: 
     $any_century?   #any century 
     (?:      #and decades divisible by 4 but not 100 
      0[48]  | 
      [2468][048] | 
      [13579][26] 
     ) 
     | 
     (?:      #or match centuries that are divisible by 4 
      16   | 
      [2468][048] | 
      [3579][26] 
     ) 
     00      
    ) 
/x; 

my $any_date = qr/$non_leap_year|$feb_in_leap/; 
my $only_date = qr/^$any_date$/; 
6

इस विषय को देखकर वैकल्पिक तरीकों के बारे में है नियमित अभिव्यक्तियों को लिखने के लिए, जटिल लिखने के तरीके बिना चर के नियमित अभिव्यक्तियां और टिप्पणियों के बिना हैं, और यह अभी भी उपयोगी है।

मैंने चास ओवेन्स की तारीख को पर्ल -510 में उपलब्ध नए घोषणात्मक फॉर्म में रेगेक्स को मान्य करने की तारीख को दोहराया, जिसमें कई लाभ हैं। regex में

  • टोकन पुन: प्रयोज्य
  • किसी को भी रेगुलर एक्सप्रेशन से मुद्रण बाद में अभी भी पूरे तर्क पेड़ देखेंगे।

यह मछली के हर किसी के केतली नहीं हो सकता है, लेकिन बहुत ही जटिल चीजों के लिए जैसे कि इसे मान्य करने की तिथि आसान हो सकती है (पीएस: वास्तविक दुनिया में, कृपया तिथि सामग्री के लिए मॉड्यूल का उपयोग करें, DIY नहीं, यह DIY से जानने के लिए सिर्फ एक उदाहरण)

#!/usr/bin/perl 
use strict; 
use warnings; 
require 5.010; 

#match the 1st through 28th for any month of any year 
my $date_syntax = qr{ 
    (?(DEFINE) 
     (?<century> 
      (1[6-9] | [2-9][0-9]) 
     ) 
     (?<decade> 
      [0-9]{2} (?!\d) 
     ) 
     (?<year> 
      (?&century)? (?&decade)(?!\d) 
     ) 
     (?<leapdecade> (
      0[48]  | 
      [2468][048] | 
      [13579][26] 
      )(?!\d) 
     ) 
     (?<leapcentury> (
      16   | 
      [2468][048] | 
      [3579][26] 
      ) 
     ) 
     (?<leapyear> 
      (?&century)?(?&leapdecade)(?!\d) 
      | 
      (?&leapcentury)00(?!\d) 
     ) 
     (?<monthnumber>  (0?[1-9] | 1[0-2])(?!\d)     ) 
     (?<shortmonthnumber> (0?[469] | 11 )(?!\d)     ) 
     (?<longmonthnumber> (0?[13578] | 1[02])(?!\d)    ) 
     (?<nonfebmonth>  (0?[13-9] | 1[0-2])(?!\d)    ) 
     (?<febmonth>   (0?2)(?!\d)        ) 
     (?<twentyeightdays> (0?[1-9] | 1[0-9] | 2[0-8])(?!\d)  ) 
     (?<twentyninedays> ((?&twentyeightdays) | 29)(?!\d)   ) 
     (?<thirtydays>  ((?&twentyeightdays) | 29 | 30)(?!\d) ) 
     (?<thirtyonedays> ((?&twentyeightdays) | 29 | 30 | 31)(?!\d)) 
     (?<separator>  [/.-]        )    #/ markdown syntax highlighter fix 
     (?<ymd> 
      (?&leapyear) (?&separator) (?&febmonth) (?&separator) (?&twentyninedays) (?!\d) 
      | 
      (?&year) (?&separator) (?&longmonthnumber) (?&separator) (?&thirtyonedays) (?!\d) 
      | 
      (?&year) (?&separator) (?&shortmonthnumber) (?&separator) (?&thirtydays) (?!\d) 
      | 
      (?&year) (?&separator) (?&febmonth) (?&separator) (?&twentyeightdays) (?!\d) 
     ) 
     (?<mdy> 
      (?&febmonth) (?&separator) (?&twentyninedays) (?&separator) (?&leapyear) (?!\d) 
      | 
      (?&longmonthnumber) (?&separator) (?&thirtyonedays) (?&separator) (?&year) (?!\d) 
      | 
      (?&shortmonthnumber) (?&separator) (?&thirtydays) (?&separator) (?&year) (?!\d) 
      | 
      (?&febmonth) (?&separator) (?&twentyeightdays) (?&separator) (?&year) (?!\d) 
     ) 
     (?<dmy> 
      (?&twentyninedays) (?&separator) (?&febmonth) (?&separator) (?&leapyear) (?!\d) 
      | 
      (?&thirtyonedays) (?&separator) (?&longmonthnumber) (?&separator)(?&year) (?!\d) 
      | 
      (?&thirtydays) (?&separator) (?&shortmonthnumber) (?&separator) (?&year) (?!\d) 
      | 
      (?&twentyeightdays) (?&separator) (?&febmonth) (?&separator) (?&year) (?!\d) 
     ) 
     (?<date> 
      (?&ymd) | (?&mdy) | (?&dmy) 
     ) 
     (?<exact_date> 
      ^(?&date)$ 
     ) 
    ) 
}x; 

my @test = ("2009-02-29", "2009-02-28", "2004-02-28", "2004-02-29", "2005-03-31", "2005-04-31", "2005-05-31", 
    "28-02-2009","02-28-2009",   
); 

for (@test) { 
    if ($_ =~ m/(?&exact_date) $date_syntax/x) { 
    print "$_ is valid\n"; 
    } 
    else { 
    print "$_ is not valid\n"; 
    } 

    if ($_ =~ m/^(?&ymd) $date_syntax/x) { 
    print "$_ is valid ymd\n"; 
    } 
    else { 
    print "$_ is not valid ymd\n"; 
    } 


    if ($_ =~ m/^(?&leapyear) $date_syntax/x) { 
    print "$_ is leap (start)\n"; 
    } 
    else { 
    print "$_ is not leap (start)\n"; 
    } 

    print "\n"; 
} 

नोट (?!\d) के टुकड़े, जो '4' 0 से मेल खाने? [4]

की वजह से जोड़ रहे हैं ताकि

"45" अभ्यस्त ~= m{(?&twentyeightdays) $syntax} से मेल के अलावा है

+0

यह मुझे पर्ल 6 की प्रतीक्षा करता है। –

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

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