PHP之深入學習正則表示式
目錄
個人實驗梳理出來的正則,深刻理解建議讀者動手實驗。
x01 基本語法
一個完整的正則表示式由兩部分構成:元字元和普通字元。元字元就是具有特殊含義的字元,如“.”和“?”。普通字元就是僅指代自身語義的普通文字,如數字、字母等。一般情況下,正則表示式都被放在定界符內中,如“/”,避免與其他字串混淆。
1.行定界符
行定界符描述一行字串的邊界。
^:表示行開始
$:表示行結尾
【例1】
定義一個被操作字串"html、htm",一個正則表示式’/^htm/’,然後呼叫preg_match()函式執行匹配,匹配結果儲存於$matches變數中,輸出顯示匹配結果及其坐在位置。
<?php
$subject = "html、htm";
$pattern = '/^htm/'; //匹配開始位置的“htm”字串
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r ($matches);
?>
輸出結果:
$pattern = '/htm$/'; //匹配結尾的“htm”字串
輸出結果:
2.單詞定界符
單詞定界符描述一個單詞的邊界。
\b:表示單詞邊界
\B:表示非單詞邊界
【例1】
使用\b定界符匹配一個完整的“htm”。
<?php
$subject = "html、hm、htm";
$pattern = '/\bhtm\b/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
$pattern = '/\bhtm/';
輸出結果:
$pattern = '/htm\b/';
輸出結果:
3.字元類
字元類是一個字元列表。可以使用字元類指定字元列表以匹配正則表示式中的位置。使用[]定義字元類。
【例1】
定義正則 ml、mL、Ml、ML的字元類。
<?php
$subject = "html、hm、htm";
$pattern = '/[mM][lL]/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
4.選擇符
選擇符類似字元類,可以實現選擇字元的匹配模式。使用“|”可以定義選擇匹配模式,類似PHP運算中的邏輯或。
【例1】
字元模式可以匹配“h”,也可以匹配”Html“。
<?php
$subject = "Html、html、hm、htm";
$pattern = '/h|Html/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
5.範圍符
使用字元類需要列舉所有可選字元,當可選字元比較多時就比較麻煩。不過在字元類中可以用連字元“-”定義字元範圍。
<?php
$subject = "Html、html、hm、htm";
$pattern = '/[a-z]/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
主要用於定義多個字元類,匹配任意指定範圍的字元。
$pattern = '/[A-Z]/'; //匹配任意一個小寫字母
$pattern = '/[0-9]/'; //匹配任意一個數字
$pattern = '/[\u4e00-\u9fa5]/'; //匹配任意中文字元
$pattern = '/[\x00-\xff]/'; //匹配任意單位元組字元
6.排除符
除了範圍符外,排除符“^“放到方括號內,即表示排除字元列表。類似PHP運算中的邏輯非。
<?php
$subject = "Html、html、hm、htm";
$pattern = '/[^a-z]/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
7.限定符
用來指定正則表示式的一個給定字元、字元類或子表示式必須要出現多少次才能滿足匹配。
* 匹配0次或多次
<?php
$subject = "gooooogle";
$pattern = '/go*/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
+ 匹配1次或多次
$pattern = '/go+/';
輸出結果:
? 匹配0次或1次
$pattern = '/go?/';
輸出結果:
{n} 匹配前一個內容的重複次數為n次
$pattern = '/go{2}/';
輸出結果:
{n,} 匹配前一個內容的重複次數大於等於n次
$pattern = '/go{2,}/';
輸出結果:
{n,m} 匹配前一個內容的重複次數m次到n次
$pattern = '/go{2,4}/';
輸出結果:
注意:除了{n}之外,所有限定符都具有貪婪性,因為它們會盡可能多的匹配字元,只有在字元後面加上?就可以實現非貪婪模式或最小匹配。
$pattern = '/goo*?/';
輸出結果:
$pattern = '/go{2,4}?/';
輸出結果:
8.任意字元
點號(.)能夠匹配除換行符\n之外的任何單字元。如果要匹配點號(.)自己,需要使用\進行轉義。
<?php
$subject = "gooo.oogle";
$pattern = '/o.{1,6}/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
$pattern = '/\..*/';
輸出結果:
9.轉義字元
轉義字元”\“能偶將特殊字元變為普通的字元,如.、*、^、$等,其功能與PHP字串中的轉義字元類似。
【例1】
為了匹配IP地址,使用轉義符號”\“把元字元(.)進行轉義,然後配合限定符匹配IP字串。
<?php
$subject = "127.0.0.1";
$pattern = '/([0-9]{1,3}\.?){4}/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
10.反斜槓
反斜槓”\“除了能夠轉義以外,還具備其他功能。
1.定義非列印字元
\f:匹配一個換頁符
\n:匹配一個換行符
\r:匹配一個回車符
\s:匹配任何空白符,包括空格、製表符、換頁符等
\S:匹配任何非空白符
\t:匹配一個製表符
\v:匹配一個垂直製表符
<?php
$subject = "goo ooogle";
$pattern = '/\soo\S*/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
2.預定義字符集
\d:匹配一個數字字元
\D:匹配一個非數字字元
\s:匹配任何空白符,包括空格、製表符、換頁符等
\S:匹配任何非空白符
\w:匹配任何下劃線的任何單詞數字字元
\W:匹配 任何非單詞數字字元
<?php
$subject = "goo123oogle";
$pattern = '/\woo\d*/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
3.定義斷言限定符
\b:單詞定界符
\B:非單詞定界符
\A:字串開頭,類似^,但不受處理多行選項的影響
\Z:字串結尾或行尾(換行符之前的位置),但不受處理多行選項的影響
\z:字串結尾,類似$
\G:當前搜尋的開頭
11.小括號
1.改變作用範圍
【例1】
顯示了小括號在改變選擇符和限定符的作用範圍
<?php
$subject = "html-HTml-goo123oogle";
$pattern = '/(ht|HT)ml/';
preg_match($pattern,$subject,$matches,PREG_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
$pattern = '/(ht)ml|(HT)ml/';
輸出結果:
$pattern = '/(goo){1,3}/';
輸出結果:
2.定義子表示式
子表示式相當於一個獨立的正則表示式。子表示式具有記憶功能,能夠臨時儲存其匹配的字元,然後可以在後面進行引用。
12.修飾符
主要調整正則表示式的解釋,增強了正則表示式的能力。
i:不區分大小寫
m:將字串視為多行
s:將字串視為一行
x:忽略空白(進行轉義的空白不被忽略)
A:匹配字串開頭部分
D:模式中的$僅匹配字串的結尾
x02 使用PCRE擴充套件正則表示式函式
正則表示式需要在相應的正則表達函式應用,才能實現對字串的匹配、查詢、替換及分割操作。在PHP中有兩套正則表示式的函式庫。主要講解以”preg_“開頭的PCRE擴充套件函式。
1.陣列過濾
preg_grep()函式能夠使用正則表示式過濾陣列中的元素。
array preg_grep(string $pattern,array $input[,int $flags = 0]]) //匹配查詢,返回一個數組;
pattern:要搜素的正則模式
input:輸入陣列
flags:若設定為PREG_GREP_INVERT,將返回輸入陣列中與給定模式pattern不匹配的元素組成的陣列
preg_grep()函式將返回給定陣列input中與模式pattern相匹配的元素組成的陣列。返回陣列將使用input引數陣列中key做索引。
<?php
$array = array(2,3,45,"a",4.5,9.8,.9);
$pattern = '/^(\d*)?\.\d+$/';
$final = preg_grep($pattern,$array);
print_r($final);
?>
輸出結果:
2.執行一次匹配
preg_match()函式能偶執行一個正則表示式匹配。
int preg_match(string $pattern,string $subject [,array &$matches [,int $flags = 0 [,int $offset = 0]]])
pattern:要搜尋的正則模式
subject:輸入字串
matches:如果提供了該引數,它將填充為搜素結果。$matches[0]包含完整匹配到的文字,$matches[1]將包含第一個捕獲子組匹配到的文字,以此類推。
flags:可設定為PREG_OFFSET_CAPTURE,表示對於每一個匹配返回時,附加字串偏移量
offset:用於從目標字串的某個位置開始搜尋,單位是位元組
preg_match()函式將返回pattern得匹配次數。返回值是0(不匹配)或1次,preg_match()在第一次匹配後將會停止搜尋。
【例1】快速檢測給定字串中是否包含”php“,匹配字元不區分大小寫
<?php
$subject = "PHP is a nb language.PHP is nice";
$pattern = '/php/i';
echo preg_match($pattern,$subject); //輸出 1
?>
【例2】從URL字串中匹配出域名子串
<?php
$subject = "http://www.baidu.com/index.html";
$pattern = '/^(http:\/\/)?([^\/]+)/i';
preg_match($pattern,$subject,$matches);
echo "$matches[0]\n"."~~";
echo "$matches[1]\n"."~~";
echo "$matches[2]\n"."~~";
$subject = $matches[2];
$pattern = '/[^.]+\.[^.]+$/';
preg_match($pattern,$subject,$matches);
echo "域名:$matches[0]\n";
?>
輸出結果:
注意:如果只是想要檢查一個字串是否包含另外一個字串,建議使用strpos()或strstr()函式。
3.執行所有匹配
preg_match_all()函式能夠執行一個全域性正則表示式匹配。
int preg_match_all(string $pattern,string $subject [,array &$matches [,int $flags = PREG_PATTERN_ORDER [,int $offset = 0]]])
pattern:要搜尋的正則模式
subject:輸入字串
matches:多維陣列,作輸出引數,輸出所有匹配結果。陣列排序通過flags指定
flags:若不指定排序標記,預設為PREG_PATTERN_ORDER
PREG_PATTERN_ORDER:結果排序為$matches[0]儲存完整模式的所有匹配,$matches[1]儲存第一個子組的所有匹配,以此類推
PREG_SET_ORDER:結果排序為$matches[0]包含第一次匹配得到的所有匹配(包含子組),$matches[1]包含第二次匹配的所有匹配(包含子組)的陣列,以此類推
PREG_OFFSET_CAPTURE:每個發現的匹配返回時會增加它相對目標字串的偏移量
offset:用於從目標字串的某個位置開始搜尋,單位是位元組
preg_match_all()函式能夠搜尋subject中所有匹配pattern給地那個正則表示式的匹配結果,並且以flags指定順序輸出到matches中。第一次匹配找到後,子序列繼續從最後一次匹配位置搜尋。
【例1】找出HTML字串所有標籤,及其包含的文字等資訊
<?php
$html = "<b>加粗文字</b><p>段落文字</p>";
$pattern = '/(<([\w]+)>)(.*)(<\/.*\2>)/';
preg_match_all($pattern,$html,$matches,PREG_SET_ORDER);
foreach($matches as $val){
echo "匹配資訊:"."$val[0]"."\n";
echo "子組1:"."$val[1]"."\n";
echo "子組2:"."$val[2]"."\n";
echo "子組3:"."$val[3]"."\n";
echo "子組4:"."$val[4]"."\n";
}
?>
輸出結果:(忽略以下的雙引號)
4.轉義字元
preg_quote()函式能夠轉義正則表示式字元。
string preg_quote(string $str[,string $delimiter = NULL])
str:輸入字串
delimiter:指定會被轉義的字元
preg_quote()函式在str中每個正則表示式語法中的特殊字元前新增一個反斜槓""
【例1】對字串中的特殊字元進行轉義
<?php
$str = '2020/12/31 0.59$';
$str = preg_quote($str,NULL);
echo $str;
?>
輸出結果:
$str = preg_quote($str,'/');
輸出結果:
5.查詢替換
preg_replace()函式能夠執行一個正則表示式的搜尋和替換。
mixed preg_replace(mixed $pattern,mixed $replacement,mixed $subject[,int $limit = -1[,int &$count]])
pattern:要搜尋的正則模式
replacement:用於替換的字串和字串陣列
subject:要進行搜尋和替換的字串和字串陣列
limit:每個模式在每個subject上進行替換的最大次數
count:若指定該引數,將會被填充為完成的替換次數
如果subject是陣列,preg_replace()返回一個數組,其他情況返回一個字串。如果匹配被找到,替換後的subject被返回,反之則返回原subject
【例1】使用反向引用修改字串中的數字和顯示格式
<?php
$subject = 'DEC-31,2020';
$pattern = '/(\w+)-(\d+),(\d+)/i';
$replacement = '$3-$1-31';
echo preg_replace($pattern,$replacement,$subject);
?>
輸出結果:
反向引用這裡看圖理解即可
6.分隔字串
preg_split()函式能夠通過一個正則表示式分隔字串。
array preg_split(string $pattern,string $subject[,int $limit = -1[,int flags = 0]])
pattern:要搜尋的正則模式
subject:輸入字串
limit:若指定,將限制分隔得到的字串最多隻有limit個。limit值為-1、0、NULL代表不限制
flags:
PREG_SPLIT_NO_EMPTY:返回分隔後的非空部分
PREG_SPLIT_DELIM_CAPTURE:分隔模式中的括號表示式將被捕獲並返回
PREG_SPLIT_OFFSET_CAPTURE:匹配返回時附加字串偏移量
preg_split()函式將返回一個使用pattern邊界分隔subject後得到的子串組成的陣列
【例1】將一個短語分隔為多個單詞
<?php
$subject = 'Hi,,,how are you';
$pattern = '/[\s,]+/';
$matches = preg_split($pattern,$subject,PREG_SPLIT_OFFSET_CAPTURE);
print_r($matches);
?>
輸出結果:
GOT IT!持續更新~
******************************************************
具體利用方式需根據具體實踐場景~