首頁 >後端開發 >php教程 >PHP面試中正規表示式的知識總結(超詳細)

PHP面試中正規表示式的知識總結(超詳細)

不言
不言轉載
2019-01-09 10:25:456651瀏覽

這篇文章帶給大家的內容是關於PHP面試中正規表示式的知識總結(超詳細),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

相關推薦:《2019年PHP面試題大匯總(收藏)

一、簡介

1. 什麼是正規表示式

正規表示式(Regular Expression)就是用某種模式去匹配一類字串的一種公式。
正規表示式使用單一字串來描述、匹配一系列符合某個句法規則的字串。
正規表示式是繁瑣的,但它是強大的,學會之後的應用會讓你除了提高效率外,會給你帶來絕對的成就感。只要認真閱讀本教程,加上應用程式的時候進行一定的參考,掌握正規表示式不是問題。
許多程式設計語言都支援利用正規表示式進行字串操作。

2. 正規表示式的作用

分割,查找,匹配,取代字串

3. PHP中的正規表示式

在PHP中有兩套正規表示式函數庫,兩者功能相似,只是執行效率略有差異:

#一套是由PCRE(Perl Compatible Regular Expression ) 庫提供的。使用「preg_」為前綴命名的函數;
一套由 POSIX(Portable Operating System Interface of Unix )擴充功能提供的。使用以「ereg_」為前綴命名的函數;

PCRE來自Perl語言,而Perl則是對字串操作功能最強大的語言之一,PHP的最初版本就是由Perl開發的產品。
PCRE語法支援更多特性,比POSIX語法更強大。因此,本文主要介紹PCRE 語法的正規表示式

4. 正規表示式的組成

##在PHP中,一個正規表示式分為三個部分:分隔符號、表達式和模式修飾符。

分隔符號

分隔符號可以使用除字母、數字、反斜線(\)和空白字元之外的任意 ascii 字元。

最常用的分隔符號有正斜線(/)、hash符號(#) 、取反符號(~)。

表達式

有一些特殊字元和非特殊的字串組成。是決定正規表示式符合規則的主要部分。

模式修飾符

用於開啟和關閉某些特定的功能/模式。

二、分隔符號

1. 分隔符號的選擇

當使用PCRE 函數的時候,正規表示式必須由分隔符號閉合包裹。

分隔符號可以使用除字母、數字、反斜線(
\)和空白字元之外的任意 ascii 字元。
最常用的分隔符號有正斜線(/)、hash符號(#) 以及取反符號(~)。

/foo bar/ (合法)
#^[^0-9]$# (合法)
+php+    (合法)
%[a-zA-Z0-9_-]%    (合法)
#[a-zA-Z0-9_-]/    (非法,两边的分隔符不同)
a[a-zA-Z0-9_-]a    (非法,分隔符不能是字母)
\[a-zA-Z0-9_-]\    (非法,分隔符不能是反斜线(`\`))

除了上面提到的分隔符,也可以使用括號樣式的分隔符,左括號和右括號分別作為開始和結束 分隔符。

{this is a pattern}
2. 分隔符號的使用

如果分隔符號在正規表示式中使用,它必須使用反斜線(\)進行轉義。 果實分隔符號經常在正規表示式內出現, 最好使用其他分隔符號來提高可讀性。

/http:\/\//
#http://#

需要將一個字串放入正規表示式中使用時,可以用 preg_quote() 函數對其進行轉義。 它的第二個參數(可選)可以用來指定需要被轉義的分隔符號。

//在这个例子中,preg_quote($word) 用于保持星号和正斜杠(/)原文涵义,使其不使用正则表达式中的特殊语义。
$textBody = "This book is */very/* difficult to find.";
$word = "*/very/*";
$reg = "/" . preg_quote($word, '/') . "/";

echo $reg; // 输出 '/\*\/very\/\*/'

echo preg_replace ($reg, "<i>" . $word . "</i>", $textBody); // 输出 'This book is <i>*/very/*</i> difficult to find.'

可以在結束分隔符號後面增加模式修飾符來影響匹配效果。

下面的範例是一個大小寫不敏感的匹配

#[a-z]#i

#三、元字元

1. 轉義符號

字元描述\將下一個字符標記為一個特殊字元、或一個原義字元、或一個向後引用。
例如,'n' 匹配字元 "n"。 'n' 符合一個換行符。序列'\' 匹配"" 而"(" 則匹配"("。
#2. 定位符

描述符合輸入字串的開始位置(或在多行模式下是行首)#符合輸入字串的結束位置(或在多行模式下是行尾)
#字元
^
$
######\b#########符合一個單字邊界,即字與空格間的位置############ ###\B#########非單字邊界比對############

3. 限定符

# #* 等價於{0,}。 例如,'zo ' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。等價於 {1,}。 ?例如,"do(es)?" 可以符合 "do" 或 "does" 。 ? 等價於 {0,1}。 {n}例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。 {n,}例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。 'o{1,}' 等價於 'o '。 'o{0,}' 則等價於 'o*'。 {n,m}
字元 描述

符合前面的子表達式零次或多次。 例如,zo 能符合 "z" 以及 "zoo"。
比符合前面的子表達式一次或多次。
當字元作為量詞,表示要符合前面的子表達式零次或一次。
n 是非負整數。配對確定的 n 次。
n 是非負整數。至少匹配n 次。

m 和 n 都是非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。 例如,"o{1,3}" 將符合 "fooooood" 中的前三個 o。 'o{0,1}' 等價於 'o?'。請注意逗號和兩個數字之間不能有空格。 #字元說明#符合一個數字字元。等價於 [0-9]#符合一個非數字字元。等價於 [^0-9]#符合字母、數字、底線。等價於 [A-Za-z0-9_]#符合非字母、數字、底線。等價於 [^A-Za-z0-9_]#符合任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]#符合任何非空白字元。等價於 [^ \f\n\r\t\v].
4.通用字元
#\d
\D
\w
\W
\s
\S

#符合換行符(n、r)以外的任何單一字元。

要符合包括 'n' 在內的任何字符,請使用像"(.

n)"的正規表示式。 匹配一個換行符號。等價於 x0a 和 cJ。
#5. 非列印字元
#說明
\n
\r

符合一個回車符號。等價於 x0d 和 cM。 符合一個製表符。等價於 x09 和 cI。
\t
6. 多重選取分支符

#說明##|豎線字元| 可以符合多選一的情況。 [xyz]例如, [^xyz]
例如,'z|food' 能匹配 "z" 或 "food"。 '(z|f|g)ood' 則符合 "zood"、"food"或 "good"。
7. 字元組
#說明

[x|y]符合x 或y。
例如,'z|food' 能匹配 "z" 或 "food"。 '(z|f)ood' 則符合 "zood" 或 "food"。
字元集合。匹配所包含的任意一個字元。 [abc]
可以符合 "plain" 中的 'a'。
######負值字元集合。匹配未包含的任意字元。 ###例如, ###[^abc]### 可以符合 "plain" 中的'p'、'l'、'i'、'n'。 ###############[a-z]#########字元範圍。符合指定範圍內的任意字元。 ###例如,###[a-z]### 可以符合 'a' 到 'z' 範圍內的任意小寫字母字元。 ###############[^a-z]#########負值字元範圍。匹配任何不在指定範圍內的任意字元。 ###例如,###[^a-z]### 可以符合任何不在 'a' 到 'z' 範圍內的任意字元。 ############

8. 非貪婪匹配

字元#描述
?當字元緊接在任何其他限制符(*, , ?, {n}, {n,}, {n,m}) 後面時,符合模式是非貪婪的。
非貪婪模式盡可能少的匹配所搜尋的字串,而預設的貪婪模式則盡可能多的匹配所搜尋的字串。
例如,對於字串 "oooo",'o ?' 將匹配單個 "o",而 'o ' 將匹配所有 'o'。

9. ( )分組

字元描述
(pattern)#符合pattern 並取得此符合。若要符合圓括號字符,請使用 \(\)
(?:pattern)匹配pattern 但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲以後使用。這在使用 "或" 字元 (|) 來組合一個正規表示式的各個部分是很有用。
例如, 'industr(?:y|ies) 就是比 'industry|industries' 更簡略的表達式。
(?=pattern)正向肯定預查(look ahead positive assert),在任何符合pattern的字串開始處匹配查找字串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以後使用。
例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配之後立即開始下一次匹配的搜索,而不是從包含預查的字符之後開始。
(?!pattern)正向否定預查(negative assert),在任何不匹配pattern的字串開始處匹配查找字串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以後使用。
例如"Windows(?!95|98|NT|2000)"能符合"Windows3.1"中的"Windows",但不能符合"Windows2000"中的"Windows"。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配之後立即開始下一次匹配的搜索,而不是從包含預查的字符之後開始。
(?<=pattern)#反向(look behind)肯定預查,與正向肯定預查類似,只是方向相反。
例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。
(?<!pattern)#反向否定預查,與正向否定預查類似,只是方向相反。
例如"(?

四、模式修饰符

1. i(不区分大小写)

如果设置了这个修饰符,正则表达式中的字母会进行大小写不敏感匹配。

2. m(多行模式)

默认情况下,PCRE 认为目标字符串是由单行字符组成的(然而实际上它可能会包含多行)。
"行首"元字符 (^) 仅匹配字符串的开始位置, 而"行末"元字符 ($) 仅匹配字符串末尾, 或者最后的换行符(除非设置了 D 修饰符)。

当这个修饰符设置之后,“行首”元字符 (^) 和“行末”元字符 ($) 就会匹配目标字符串中任意换行符之前或之后,另外,还分别匹配目标字符串的最开始和最末尾位置。

如果目标字符串 中没有 "n" 字符,或者正则表达式中没有出现 ^$,设置这个修饰符不产生任何影响。

3. s(点号通配模式)

默认情况下,点号(.)不匹配换行符。
如果设置了这个修饰符,正则表达式中的点号元字符匹配所有字符,包含换行符。

4. U(贪婪模式)

这个修饰符与前面提到的 ? 作用相同,使正则表达式默认为非贪婪匹配,通过量词后紧跟 ? 的方式可以使其转为贪婪匹配。

在非贪婪模式,通常不能匹配超过 pcre.backtrack_limit 的字符。

贪婪模式

$str = &#39;<b>abc</b><b>def</b>';
$pattern = '/<b>.*</b>/';
preg_replace($pattern, '\\1', $str);<p><code>.*</code>会匹配 <code>abc</b><b>def</code></p>
<h4><strong>非贪婪模式</strong></h4>
<p><strong>方法一、使用 <code>?</code> 转为非贪婪模式</strong></p>
<pre class="brush:php;toolbar:false">$str = '<b>abc</b><b>def</b>';
$pattern = '/<b>.*?</b>/';
preg_replace($pattern, '\\1', $str);

.*会分别匹配 abcdef

方法二、使用修饰符 U 转为非贪婪模式

$str = '<b>abc</b><b>def</b>';
$pattern = '/<b>.*</b>/U';
preg_replace($pattern, '\\1', $str);

5. u(支持UTF-8转义表达)

此修正符使正则表达式和目标字符串都被认为是 utf-8 编码。
无效的目标字符串会导致 preg_* 函数什么都匹配不到;无效的正则表达式字符串会导致 E_WARNING 级别的错误。

$str = '中文';

$pattern = '/^[\x{4e00}-\x{9fa5}]+$/u';

if (preg_match($pattern, $str)) {
    echo '该字符串全是中文';
} else {
    echo '该字符串不全是中文';
}

6. D(结尾限制)

默认情况下,如果使用 $ 限制结尾字符,当字符串以一个换行符结尾时, $符号还会匹配该换行符(但不会匹配之前的任何换行符)。
如果设置这个修饰符,正则表达式中的 $ 符号仅匹配目标字符串的末尾。
如果设置了修饰符 m,这个修饰符被忽略。

7. x

如果设置了这个修饰符,正则表达式中的没有经过转义的或不在字符类中的空白数据字符总会被忽略, 并且位于一个未转义的字符类外部的#字符和下一个换行符之间的字符也被忽略。

8. A

如果设置了这个修饰符,正则表达式被强制为"锚定"模式,也就是说约束匹配使其仅从 目标字符串的开始位置搜索。

9. S

当一个正则表达式需要多次使用的时候,为了得到匹配速度的提升,值得花费一些时间对其进行一些额外的分析。
如果设置了这个修饰符,这个额外的分析就会执行。
当前,这种对一个正则表达式的分析仅仅适用于非锚定模式的匹配(即没有单独的固定开始字符)。

五、反向引用

使用 ( ) 标记的开始和结束的多个原子,不仅是一个独立的单元,也是一个子表达式。
在一个 ( ) 中的子表达式外面,反斜线紧跟一个大于 0 的数字,就是对之前出现的某个子表达式的后向引用。
后向引用用于重复搜索前面某个  ( ) 中的子表达式匹配的文本。

1. 在正则表达式中使用反向引用

(sens|respons)e and \1ibility 将会匹配 ”sense and sensibility” 和 ”response and responsibility”, 而不会匹配 ”sense and responsibility”

2. 在PCRE函数中使用反向引用

<?php
$str = '<b>abc</b><b>def</b>';
$pattern = '/<b>(.*)<\/b><b>(.*)<\/b>/';
$replace = preg_replace($pattern, '\\1', $str);
echo $replace . "\n";

$replace = preg_replace($pattern, '\\2', $str);
echo $replace . "\n";

输出:

abc
def

六、正则表达式常用PCRE函数

PHP官网的讲解已经很详细了,这里不再做多余的论述

执行正则表达式匹配 preg_match()

执行正则表达式全局匹配 preg_match_all()

执行一个正则表达式的搜索和替换 preg_replace()

执行一个正则表达式搜索并且使用一个回调进行替换 preg_replace_callback()

执行多个正则表达式搜索并且使用对应回调进行替换 preg_replace_callback_array()

通过一个正则表达式分隔字符串 preg_split()

七、应用实践

1. 正则表达式匹配中文

UTF-8汉字编码范围是 0x4e00-0x9fa5
在ANSI(GB2312)环境下,0xb0-0xf70xa1-0xfe

UTF-8要使用 u模式修正符 使模式字符串被当成 UTF-8
在ANSI(GB2312)环境下,要使用chr将Ascii码转换为字符

UTF-8

<?php

$str = &#39;中文&#39;;

$pattern = &#39;/[\x{4e00}-\x{9fa5}]/u&#39;;

preg_match($pattern, $str, $match);

var_dump($match);

ANSI(GB2312)

<?php

$str = &#39;中文&#39;;

$pattern = &#39;/[&#39;.chr(0xb0).&#39;-&#39;.chr(0xf7).&#39;][&#39;.chr(0xa1).&#39;-&#39;.chr(0xfe).&#39;]/&#39;;

preg_match($pattern, $str, $match);

var_dump($match);

2. 正则表达式匹配页面中所有img标签中的src的值。

<?php

$str = &#39;<img alt="高清大图" id="color" src="color.jpg" />';

$pattern = '/<img.*?src="(.*?)".*?\/?>/i';

preg_match($pattern, $str, $match);

var_dump($match);

以上是PHP面試中正規表示式的知識總結(超詳細)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除