資深架構師Sum的故事:正則!入門就是這樣簡單

cnnbull發表於2021-09-09

故事背景

  職場如戰場!Sum帶領三個小隊友用了兩週,成功把代理功能給幹出來了。如果說產品經理是最魔鬼的指揮官,那測試就是最魔鬼的教官。這兩週,讓Sum深深領略了什麼是X市的日出。

  不過話又說回來,戰鬥時光是酸苦且甘甜的,每每回憶,嘴角都會泛起流糖般的微笑,那是年輕時月亮的背影,那是年輕時初升太陽的輪廓。

  不知道其他熱愛程式的人是不是這樣想的,但Sum是這麼認為的。

  Sum依舊按部就班。

  這日Sum早早到公司了,8點,太陽才剛微熱。晨霧還未散去,站在落地窗向外看,世界就像開啟饅頭蒸籠般冒著熱騰騰的蒸汽。

  Sum開啟電腦,趁著開機消耗的時間,去泡了杯咖啡。回到座位,電腦早已經開好。

  看了下工作日程,和往常一樣,審計程式碼、梳理需求、開會,開會,還是開會。

  那就從審計昨日程式碼開始吧,Sum從git下載了昨日的程式碼(因為X公司有固定釋出日,所以程式碼提交後,第二天由Sum等專案負責人去負責審計),下載完成後,Sum開啟了zendstudio(因為Sum負責公司的PHP模組開發,所以負責審計這部分程式碼),匯入最新的工程,對照更新日誌,開啟對應的修改過檔案,一遍喝著咖啡,一遍看著程式碼。

  Sum在看到一個功能函式庫檔案的時候,發現一個curlApi($url,$param,$type=1)函式,實現過程有一段這樣的程式碼,看起來很彆扭,如下:

  

1 if(strpos($response,"__callback(")!==false){2   $response=str_replace(array("__callback(",")"),array("",""),$response);    
3 }4 $returnData = json_decode($response,true);5 return $returnData;

  結果看起來很正常,就是curl一個API,返回的$response有可能包含了__callback字串,不是純的json文字,所以這位隊友就在返回結果做了個判斷,如果存在__callback(的字串,就要替換成空,再近些json轉陣列的操作。但是,在Sum開起來,這裡面埋了一個雷,什麼雷呢?如果介面提供方哪天心情不好了,把__callback換成了__query,而且不通知到技術部,那這個用法就廢了,怎麼辦呢?Sum第一個念頭就是使用正規表示式,去匹配這類特殊的響應值。

  心中有了想法,Sum就想做一個教程,給團隊的成員普及一下,於是乎,Sum開啟了PPT,準備起了培訓材料。。。。

 

| 需求分析

  Sum要做一分通俗易懂,易於宣講的正規表示式的教程。

 

| 開幹

  Sum覺得,要能下意識的想到用正規表示式,那必須要把正規表示式的表,給背熟,融入到骨子裡去,然後再經過多個demo的練習,形成如果需要處理字串或者文字(比如爬蟲),首先想到的就是正規表示式。所以,Sum就在PPT的首章,貼出了正規表示式的規則表。

 

  普通字元:普通字元包括沒有顯式指定為元字元的所有可列印和不可列印字元。這包括所有大寫和小寫字母、所有數字、所有標點符號和一些其他符號。比如/demo/,就是匹配字串或者文字,有無demo這個字眼

 

  非列印字元(指在計算機中有一些字元是確確實實存在,但是它們不能夠顯示或者列印出來,以為例,值在0-31的為,無法顯示和列印):

                                非列印字元也可以是正規表示式的組成部分。下表列出了表示非列印字元的轉義序列

字元 描述
cx 匹配由x指明的控制字元。例如, cM 匹配一個 Control-M 或回車符。x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個原義的 'c' 字元。
f 匹配一個換頁符。等價於 x0c 和 cL。
n 匹配一個換行符。等價於 x0a 和 cJ。
r 匹配一個回車符。等價於 x0d 和 cM。
s 匹配任何空白字元,包括空格、製表符、換頁符等等。等價於 [ fnrtv]。注意 Unicode 正規表示式會匹配全形空格符。
S 匹配任何非空白字元。等價於 [^ fnrtv]。
t 匹配一個製表符。等價於 x09 和 cI。
v 匹配一個垂直製表符。等價於 x0b 和 cK。

  

  

  特殊字元:所謂特殊字元,就是一些有特殊含義的字元,如上面說的 runoo*b 中的 *,簡單的說就是表示任何字串的意思。如果要查詢字串中的 * 符號,則需要對 * 進行轉義,即在其前加一個 : runo*ob 匹配 runo*ob。

            許多元字元要求在試圖匹配它們時特別對待。若要匹配這些特殊字元,必須首先使字元"轉義",即,將反斜槓字元 放在它們前面。

                                  下表列出了正規表示式中的特殊字元:

特別字元 描述
$ 匹配輸入字串的結尾位置。如果設定了 RegExp 物件的 Multiline 屬性,則 $ 也匹配 'n' 或 'r'。要匹配 $ 字元本身,請使用 $。
( ) 標記一個子表示式的開始和結束位置。子表示式可以獲取供以後使用。要匹配這些字元,請使用 ( 和 )。
* 匹配前面的子表示式零次或多次。要匹配 * 字元,請使用 *。
+ 匹配前面的子表示式一次或多次。要匹配 + 字元,請使用 +。
. 匹配除換行符 n 之外的任何單字元。要匹配 . ,請使用 . 。
[ 標記一箇中括號表示式的開始。要匹配 [,請使用 [。
? 匹配前面的子表示式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字元,請使用 ?。
將下一個字元標記為或特殊字元、或原義字元、或向後引用、或八進位制轉義符。例如, 'n' 匹配字元 'n'。'n' 匹配換行符。序列 '\' 匹配 "",而 '(' 則匹配 "("。
^ 匹配輸入字串的開始位置,除非在方括號表示式中使用,此時它表示不接受該字符集合。要匹配 ^ 字元本身,請使用 ^。
{ 標記限定符表示式的開始。要匹配 {,請使用 {。
| 指明兩項之間的一個選擇。要匹配 |,請使用 |。

 

 

   限定符:限定符用來指定正規表示式的一個給定元件必須要出現多少次才能滿足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6種。

                                   正規表示式的限定符有:

 

字元 描述
* 匹配前面的子表示式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價於{0,}。
+ 匹配前面的子表示式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。
? 匹配前面的子表示式零次或一次。例如,"do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 、 "doxy" 中的 "do" 。? 等價於 {0,1}。
{n} n 是一個非負整數。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。
{n,} n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價於 'o+'。'o{0,}' 則等價於 'o*'。
{n,m} m 和 n 均為非負整數,其中n

 

   

  定位符:定位符使您能夠將正規表示式固定到行首或行尾。它們還使您能夠建立這樣的正規表示式,這些正規表示式出現在一個單詞內、在一個單詞的開頭或者一個單詞的結尾。定位符用來描述字串或單詞的邊界,^ 和 $ 分別指字串的開始與結束,

        b 描述單詞的前或後邊界,B 表示非單詞邊界。

                                    正規表示式的定位符有:

字元 描述
^ 匹配輸入字串開始的位置。如果設定了 RegExp 物件的 Multiline 屬性,^ 還會與 n 或 r 之後的位置匹配。
$ 匹配輸入字串結尾的位置。如果設定了 RegExp 物件的 Multiline 屬性,$ 還會與 n 或 r 之前的位置匹配。
b 匹配一個字邊界,即字與空格間的位置。
B 非字邊界匹配。

 

   一定要背熟!!一定要背熟!!!!一定要背熟!!!!!!!!!!

 

   Sum洋洋灑灑的在PPT上寫下這行字,還特地標註這行,讓字顯得更加醒目!

   跟程式碼打交道多年的Sum,知道最有說服力的方式,就是編寫一個個demo,進行知識點的拆解。而正規表示式使用最多的場景,便是爬蟲(應用層面,當然還有編譯器等等深層次的使用),於是他選擇了一個網頁的原始碼()。

   把原始碼儲存成文字,Sum決定由淺入深的編寫正則的demo,便在PPT把自己的demo順序敲上去:

  《獲取網頁標題--入門就是這樣簡單》

  《刪掉那些沒用標籤--想取得便要先捨去》

  《根據類名取標籤--指哪取哪》

  《批次取匹配標籤--我的子集我做主》

  《成對標籤--讓資料更準確》

  demo 的索引目錄寫進PPT之後,Sum就對這些目錄進行展開編碼,時不我待,馬上開幹。

  《獲取網頁標題--入門就是這樣簡單》

  寫過靜態頁面的都知道,網頁的標題,都是在頭部進行定義,並且包含在

標籤之間。如圖:

  圖片描述

  並且,規範的html程式碼,標題都是唯一的,換句話說,title標籤,僅此一個。所以對於抓取html標題,那就變得容易了,只要寫一個規則,匹配html的title標籤,再給正規表示式做一個子規則提取到標題的內容即可。

  於是Sum便開啟了編輯器,用php寫下了一個函式,用於匹配該部分的html程式碼,並取出title的內容。

  圖片描述

 

   

   圖上,便是Sum寫的getTitle()函式,核心的正規表示式是/(.*)/;由於是正規表示式的符號,所以PHP制定正則規則時,就要對這些字元進行轉義(PS:還有哪些字元是需要轉義的呢?大家可以在評論區回覆)

  Sum在這個規則上寫上了註釋,為了解釋為什麼這條規則就能匹配到標題。

  1.

在文字中查詢由<title>開始的字串,並從該位置進行往後匹配<p>  2. (.*)子匹配規則,.表示除了換行之外的任何字元,那我們分析下我們要抓取的html程式碼,<strong><title>資深架構師Sum的故事:(Mysql)InnoDB下,儲存過程中事務的處理 - 程式設計師VIP - 部落格園,我們要抓取的內容,恰好在一行,所以適合用.去做萬用字元,*號表示0到多個和.匹配的字元。那就是如果內容在一行的話,都能匹配到。

  3.

在規則中,寫了指定的字元作為結尾的話,那匹配的結尾符便是該字串。

  4.我們都知道,正則有貪婪模式和非貪婪模式(也就是懶惰模式),上圖中使用的preg_match便是懶惰模式,這恰好表達了只有第一個滿足以

開始以結束的字元匹配到,就結束匹配。這正是我們想要的。畢竟網站的title只有一個。

  

  上面匹配的結果列印如下:

  圖片描述

 

  Sum寫完了這些註釋,再看看程式碼,卻發現了一個問題,那如果得到的文字,title中的內容如果含有換行符怎麼辦?就比如下面的程式碼變種

  圖片描述

 

 

   問題來了,這樣的程式碼,正規表示式又應該如何寫呢?

  這正是Sum拋給組員的問題,正在看《資深架構師Sum的故事》的你,是否也有你的答案呢?歡迎在評論區進行作答

  《本章節未完待續》

 原文出處:https://www.cnblogs.com/programmerVIP/p/9616607.html


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2524/viewspace-2813977/,如需轉載,請註明出處,否則將追究法律責任。

相關文章