久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      [php]正則表達(dá)式的五個(gè)成功習(xí)慣

      正則表達(dá)式難于書寫、難于閱讀、難于維護(hù),經(jīng)常錯(cuò)誤匹配意料不到的文本或者錯(cuò)過了有效的文本,這些問題都是由正則表達(dá)式的表現(xiàn)和能力引起的。每個(gè)元字符(metacharacter)的能力和細(xì)微差別組合在一起,使得代碼不借助于智力技巧就無法解釋。 
           許多包含一定特性的工具使閱讀和編寫正則表達(dá)式變得容易了,但是它們又很不符合習(xí)慣。對(duì)于很多程序員來說,書寫正則表達(dá)式就是一種魔法藝術(shù)。他們堅(jiān)持自己所知道的特征并持有絕對(duì)樂觀的態(tài)度。如果你愿意采用本文所探討的五個(gè)習(xí)慣,你將可以讓你設(shè)計(jì)的正則表達(dá)式經(jīng)受的住反復(fù)試驗(yàn)。 
          本文將使用Perl、PHP和Python語言作為代碼示例,但是本文的建議幾乎適用于任何替換表達(dá)式(regex)的執(zhí)行。 

          一、使用空格和注釋 
          對(duì)于大部分程序員來說,在一個(gè)正則表達(dá)式環(huán)境里使用空格和縮進(jìn)排列都不成問題,如果他們沒有這么做一定會(huì)被同行甚至外行人士看笑話。幾乎每個(gè)人都知道把代碼擠在一行會(huì)難于閱讀、書寫和維護(hù)。對(duì)于正則表達(dá)式又有什么不同呢? 
          大部分替換表達(dá)式工具都具有擴(kuò)展的空格特性,這允許程序員把他們的正則表達(dá)式擴(kuò)展為多行,并在每一行結(jié)尾加上注釋。為什么只有少部分程序員利用這個(gè)特性呢?Perl 6的正則表達(dá)式默認(rèn)就是擴(kuò)展空格的模式。不要再讓語言替你默認(rèn)擴(kuò)展空格了,自己主動(dòng)利用吧。 
          記住擴(kuò)展空格的竅門之一就是讓正則表達(dá)式引擎忽略擴(kuò)展空格。這樣如果你需要匹配空格,你就不得不明確說明。 
          在Perl語言里面,在正則表達(dá)式的結(jié)尾加上x,這樣“m/foo|bar/”變?yōu)槿缦滦问剑?nbsp;
      m/ 
        foo 

        bar 
       /x 
          在PHP語言里面,在正則表達(dá)式的結(jié)尾加上x,這樣“”/foo|bar/””變?yōu)槿缦滦问剑?nbsp;
      “/ 
        foo 

        bar 
       /x” 
          在Python語言里面,傳遞模式修飾參數(shù)“re.VERBOSE”得到編譯函數(shù)如下: 
      pattern = r”’ 
       foo 

       bar 
      ”’ 
      regex = re.compile(pattern, re.VERBOSE) 
          處理更加復(fù)雜的正則表達(dá)式時(shí),空格和注釋就更能體現(xiàn)出其重要性。假設(shè)下面的正則表達(dá)式用于匹配美國(guó)的電話號(hào)碼: 
      (?d{3})? ?d{3}[-.]d{4} 
           這個(gè)正則表達(dá)式匹配電話號(hào)碼如“(314)555-4000”的形式,你認(rèn)為這個(gè)正則表達(dá)式是否匹配“314-555-4000”或者“555- 4000”呢?答案是兩種都不匹配。寫上這么一行代碼隱蔽了缺點(diǎn)和設(shè)計(jì)結(jié)果本身,電話區(qū)號(hào)是需要的,但是正則表達(dá)式在區(qū)號(hào)和前綴之間缺少一個(gè)分隔符號(hào)的說明。 
          把這一行代碼分成幾行并加上注釋將把缺點(diǎn)暴露無疑,修改起來顯然更容易一些。 
          在Perl語言里面應(yīng)該是如下形式: 
      /   
          (?     # 可選圓括號(hào) 
            d{3} # 必須的電話區(qū)號(hào) 
          )?     # 可選圓括號(hào) 
          [-s.]? # 分隔符號(hào)可以是破折號(hào)、空格或者句點(diǎn) 
            d{3} # 三位數(shù)前綴 
          [-.]    # 另一個(gè)分隔符號(hào) 
            d{4} # 四位數(shù)電話號(hào)碼 
      /x 
          改寫過的正則表達(dá)式現(xiàn)在在電話區(qū)號(hào)后有一個(gè)可選擇的分隔符號(hào),這樣它應(yīng)該是匹配“314-555-4000”的,然而電話區(qū)號(hào)還是必須的。另一個(gè)程序員如果需要把電話區(qū)號(hào)變?yōu)榭蛇x項(xiàng)則可以迅速看出它現(xiàn)在不是可選的,一個(gè)小小的改動(dòng)就可以解決這個(gè)問題。 

          二、書寫測(cè)試 
          一共有三個(gè)層次的測(cè)試,每一層為你的代碼加上一層可靠性。首先,你需要認(rèn)真想想你需要匹配什么代碼以及你是否能夠處理錯(cuò)誤匹配。其次,你需要利用數(shù)據(jù)實(shí)例來測(cè)試正則表達(dá)式。最后,你需要正式通過一個(gè)測(cè)試小組的測(cè)試。 
           決定匹配什么其實(shí)就是在匹配錯(cuò)誤結(jié)果和錯(cuò)過正確結(jié)果之間尋求一個(gè)平衡點(diǎn)。如果你的正則表達(dá)式過于嚴(yán)格,它將會(huì)錯(cuò)過一些正確匹配;如果它過于寬松,它將會(huì)產(chǎn)生一個(gè)錯(cuò)誤匹配。一旦某個(gè)正則表達(dá)式發(fā)放到實(shí)際代碼當(dāng)中,你可能不會(huì)兩者都注意到。考慮一下上面電話號(hào)碼的例子,它將會(huì)匹配“800-555-4000  = -5355”。錯(cuò)誤的匹配其實(shí)很難發(fā)現(xiàn),所以提前規(guī)劃做好測(cè)試是很重要的。 
          還是使用電話號(hào)碼的例子,如果你在Web表單里面確認(rèn)一個(gè)電話號(hào)碼,你可能只要滿足于任何格式的十位數(shù)字。但是,如果你想從大量文本里面分離電話號(hào)碼,你可能需要很認(rèn)證的排除不符合要求的錯(cuò)誤匹配。 
          在考慮你想匹配的數(shù)據(jù)的時(shí)候,寫下一些案例情況。針對(duì)案例情況寫下一些代碼來測(cè)試你的正則表達(dá)式。任何復(fù)雜的正則表達(dá)式都最好寫個(gè)小程序測(cè)試一下,可以采用下面的具體形式。 
          在Perl語言里面: 
      #!/usr/bin/perl 

      my @tests = ( “314-555-4000”, 
                    “800-555-4400”, 
             “(314)555-4000”, 
                    “314.555.4000”, 
                    “555-4000”, 
                    “aasdklfjklas”, 
                    “1234-123-12345”           
                  ); 

      foreach my $test (@tests) { 
          if ( $test =~ m/ 
                         (?     # 可選圓括號(hào) 
                           d{3} # 必須的電話區(qū)號(hào) 
                         )?     # 可選圓括號(hào) 
                         [-s.]? # 分隔符號(hào)可以是破折號(hào)、空格或者句點(diǎn) 
                           d{3} # 三位數(shù)前綴 
                         [-s.]  # 另一個(gè)分隔符號(hào) 
                           d{4} # 四位數(shù)電話號(hào)碼 
                         /x ) { 
              print “Matched on $testn”; 
           } 
           else { 
              print “Failed match on $testn”; 
           } 

          在PHP語言里面: 
      <?php 
      $tests = array( “314-555-4000”, 
                 “800-555-4400”, 
                 “(314)555-4000”, 
                 “314.555.4000”, 
                 “555-4000”, 
                 “aasdklfjklas”, 
                 “1234-123-12345” 
                ); 

      $regex = “/ 
                  (?     # 可選圓括號(hào) 
                    d{3} # 必須的電話區(qū)號(hào) 
                  )?     # 可選圓括號(hào) 
                  [-s.]? # 分隔符號(hào)可以是破折號(hào)、空格或者句點(diǎn) 
                    d{3} # 三位數(shù)前綴 
                  [-s.]  # 另一個(gè)分隔符號(hào) 
                    d{4} # 四位數(shù)電話號(hào)碼 
                 /x”; 

      foreach ($tests as $test) { 
          if (preg_match($regex, $test)) {  
              echo “Matched on $test<br />;”; 
          } 
          else { 
              echo “Failed match on $test<br />;”; 
           } 

      ?>; 

              在Python語言里面: 
      import re 

      tests = [“314-555-4000”, 
               “800-555-4400”, 
               “(314)555-4000”, 
               “314.555.4000”, 
               “555-4000”, 
               “aasdklfjklas”, 
               “1234-123-12345”         
              ] 

      pattern = r”’ 
      (?                 # 可選圓括號(hào) 
                    d{3} # 必須的電話區(qū)號(hào) 
                  )?     # 可選圓括號(hào) 
                  [-s.]? # 分隔符號(hào)可以是破折號(hào)、空格或者句點(diǎn) 
                    d{3} # 三位數(shù)前綴 
                  [-s.]  # 另一個(gè)分隔符號(hào) 
                    d{4} # 四位數(shù)電話號(hào)碼 
                 ”’ 

      regex = re.compile( pattern, re.VERBOSE ) 

      for test in tests: 
          if regex.match(test): 
              print “Matched on”, test, “n” 
          else: 
              print “Failed match on”, test, “n” 

          運(yùn)行測(cè)試代碼將會(huì)發(fā)現(xiàn)另一個(gè)問題:它匹配“1234-123-12345”。 
           理論上,你需要整合整個(gè)程序所有的測(cè)試到一個(gè)測(cè)試小組里面。即使你現(xiàn)在還沒有測(cè)試小組,你的正則表達(dá)式測(cè)試也會(huì)是一個(gè)小組的良好基礎(chǔ),現(xiàn)在正是開始創(chuàng)建的好機(jī)會(huì)。即使現(xiàn)在還不是創(chuàng)建的合適時(shí)間,你也應(yīng)該在每次修改以后運(yùn)行測(cè)試一下正則表達(dá)式。這里花費(fèi)一小段時(shí)間將會(huì)減少你很多麻煩事。 

          三、為交替操作分組 
          交替操作符號(hào)(|)的優(yōu)先級(jí)很低,這意味著它經(jīng)常交替超過程序員所設(shè)計(jì)的那樣。比如,從文本里面抽取Email地址的正則表達(dá)式可能如下: 
      ^CC:|To:(.*) 
          上面的嘗試是不正確的,但是這個(gè)bug往往不被注意。上面代碼的意圖是找到“CC:”或者“To:”開始的文本,然后在這一行的后面部分提取Email地址。 
           不幸的是,如果某一行中間出現(xiàn)“To:”,那么這個(gè)正則表達(dá)式將捕獲不到任何以“CC:”開始的一行,而是抽取幾個(gè)隨機(jī)的文本。坦白的說,正則表達(dá)式匹配 “CC:”開始的一行,但是什么都捕獲不到;或者匹配任何包含“To:”的一行,但是把這行的剩余文本都捕獲了。通常情況下,這個(gè)正則表達(dá)式會(huì)捕獲大量 Email地址,所有沒有人會(huì)注意這個(gè)bug。 
          如果要符合實(shí)際意圖,那么你應(yīng)該加入括號(hào)說明清楚,正則表達(dá)式如下: 
      (^CC:)|(To:(.*)) 
          如果真正意圖是捕獲以“CC:”或者“To:”開始的文本行的剩余部分,那么正確的正則表達(dá)式如下: 
      ^(CC:|To:)(.*) 
          這是一個(gè)普遍的不完全匹配的bug,如果你養(yǎng)成為交替操作分組的習(xí)慣,你就會(huì)避免這個(gè)錯(cuò)誤。 

          四、使用寬松數(shù)量詞 
          很多程序員避免使用寬松數(shù)量詞比如“*?”、“+?”和“??”,即使它們會(huì)使這個(gè)表達(dá)式易于書寫和理解。 
           寬松數(shù)量詞可以盡可能少的匹配文本,這樣有助于完全匹配的成功。如果你寫了“foo(.*?)bar”,那么數(shù)量詞將在第一次遇到“bar”時(shí)就停止匹配,而不是在最后一次。如果你希望從“foo###bar+++bar”中捕獲“###”,這一點(diǎn)就很重要。一個(gè)嚴(yán)格數(shù)量詞將捕獲“###bar++ +”。 
          假設(shè)你要從HTML文件里面捕獲所有電話號(hào)碼,你可能會(huì)使用我們上文討論過的電話號(hào)碼正則表達(dá)式的例子。但是,如果你知道所有電話號(hào)碼都在一個(gè)表格的第一列里面,你可以使用寬松數(shù)量詞寫出更簡(jiǎn)單的正則表達(dá)式: 
      <tr>;<td>;(.+?)<td>; 
          很多剛起步的程序員不使用寬松數(shù)量詞來否定特定種類。他們能寫出下面的代碼: 
      <tr>;<td>;([^>;]+)</td>; 
          這種情況下它可以正常運(yùn)行,但是如果你想捕獲的文本包含有你分隔的公共字符(這種情況下比如</td>;),這將會(huì)帶來很大麻煩。如果你使用了寬松數(shù)量詞,你只要花上很少的時(shí)間組裝字符種類就能產(chǎn)生新的正則表達(dá)式。 
          在你知道你要捕獲文本的環(huán)境結(jié)構(gòu)時(shí),寬松數(shù)量詞是具有很大價(jià)值的。 

          五、利用可用分界符 
          Perl 和PHP語言常常使用左斜線(/)來標(biāo)志一個(gè)正則表達(dá)式的開頭和結(jié)尾,Python語言使用一組引號(hào)來標(biāo)志開頭和結(jié)尾。如果在Perl和PHP中堅(jiān)持使用左斜線,你將要避免表達(dá)式中的任何斜線;如果在Python中使用引號(hào),你將要避免使用反斜線()。選擇不同的分界符或引號(hào)可以允許你避免一半的正則表達(dá)式。這將使得表達(dá)式易于閱讀,減少由于忘記避免符號(hào)而潛在的bug。 
          Perl和PHP語言允許使用任何非數(shù)字和空格字符作為分界符。如果你切換到一個(gè)新的分界符,在匹配URL或HTML標(biāo)志(如“http://”或“<br/>;”)時(shí),你就可以避免漏掉左斜線了。 
          例如,“/http://(S)*/”可以寫為“#http://(S)*#”。 
          通用分界符是“#”、“!”和“|”。如果你要使用方括號(hào)、尖括號(hào)或者花括號(hào),只要保持前后配對(duì)出現(xiàn)就可以了。下面就是一些通用分界符的示例: 
      #…# !…! {…} s|…|…| (Perl only) s[…][…] (Perl only) s<…>;/…/ (Perl only)  
           在Python中,正則表達(dá)式首先會(huì)被當(dāng)作一個(gè)字符串。如果你使用引號(hào)作為分界符,你將漏掉所有反斜線。但是你可以使用“r””字符串避免這個(gè)問題。如果針對(duì)“re.VERBOSE”選項(xiàng)使用三個(gè)連續(xù)單引號(hào),它將允許你包含換行。例如 regex = “(\w+)(\d+)”可以寫出下面的形式: 
      regex = r”’ 
                 (w+) 
                 (d+) 
               ”’ 

          小結(jié):本文的建議主要著眼于正則表達(dá)式的可讀性,在開發(fā)中養(yǎng)成這些習(xí)慣,你將會(huì)更加清晰的考慮設(shè)計(jì)和表達(dá)式的結(jié)構(gòu),這將有助于減少bug和代碼的維護(hù),如果你自己就是這個(gè)代碼的維護(hù)者你將倍感輕松。 

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)