[TOC]
* * * * *
## 1 正則表達式的意義
正則表達式用來從**源字符串中匹配結果字符串**
**正則表達式**是結果字符串的**抽象結構描述**。
**結果字符串**是正則表達式的**具體內容組成**。
## 2 正則表達式簡單使用(php版)
>[info] 自php5.3.0起,POSIX正則表達式擴展被廢棄,使用PCRE模式正則表達式,因此下文只介紹PCRE模式正則表達式
### 1 源字符串匹配一個結果字符串 preg_match()
~~~
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
~~~
> $pattern: 結果字符串的正則描述
> $subject: 源字符串
> $matches: 匹配結果數組
>> $matches[0] 完整模式匹配到的文本
>> $macthes[1] 第一個捕獲子組匹配文本
>> $macthes[0] 第n個捕獲子組匹配文本
> $flags: 匹配狀態標記
>> PREG_OFFSET_CAPTURE
>>> 匹配時字符串相對源字符串偏移量
> 這個值會填充到$mactches數組中
> $mactches元素的第0個元素是 結果字符串
> $mactches元素的第2個元素是 結果字符串在源字符串偏移量
> $offset: 搜索開始位置,默認從字符串開始位置。
> 返回值:
> 返回匹配成功的次數。0或者1次
> preg_match() 第一次匹配成功 停止搜索
> 不同于preg_match_all() 匹配所有
> 發送錯誤 返回false
* * * * *
>[info] 示例1 查找文本字符串"php"
~~~
<?php
//模式分隔符后的"i"標記這是一個大小寫不敏感的搜索
if ( preg_match ( "/php/i" , "PHP is the web scripting language of choice." )) {
echo "A match was found." ;
} else {
echo "A match was not found." ;
}
?>
~~~
>[info] 示例2 查找單詞"web"
~~~
<?php
/* 模式中的\b標記一個單詞邊界,所以只有獨立的單詞"web"會被匹配,而不會匹配
* 單詞的部分內容比如"webbing" 或 "cobweb" */
if ( preg_match ( "/\bweb\b/i" , "PHP is the web scripting language of choice." )) {
echo "A match was found." ;
} else {
echo "A match was not found." ;
}
if ( preg_match ( "/\bweb\b/i" , "PHP is the website scripting language of choice." )) {
echo "A match was found." ;
} else {
echo "A match was not found." ;
}
?>
~~~
>[info] 示例3 獲取URL中的域名
~~~
<?php
//從URL中獲取主機名稱
preg_match ( '@^(?:http://)?([^/]+)@i' ,
"http://www.php.net/index.html" , $matches );
$host = $matches [ 1 ];
//獲取主機名稱的后面兩部分
preg_match ( '/[^.]+\.[^.]+$/' , $host , $matches );
echo "domain name is: { $matches [ 0 ]} \n" ;
?>
~~~
輸出:
`domain name is: php.net`
>[info] 示例4 命名子數組匹配
~~~
<?php
$str = 'foobar: 2008' ;
preg_match ( '/(?P<name>\w+): (?P<digit>\d+)/' , $str , $matches );
/* 下面例子在php 5.2.2(pcre 7.0)或更新版本下工作, 然而, 為了后向兼容, 上面的方式是推薦寫法. */
// preg_match('/(?<name>\w+): (?<digit>\d+)/', $str, $matches);
print_r ( $matches );
?>
~~~
輸出:
~~~
Array
(
[0] => foobar: 2008
[name] => foobar
[1] => foobar
[digit] => 2008
[2] => 2008
)
~~~
>[danger]Tip:如果你僅僅想要檢查一個字符串是否包含另外一個字符串,不要使用 preg_match() 。 使用 strpos() 或 strstr() 替代完成工作會更快。
### 2 源字符串匹配所有結果字符串 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
>>> 結果排序為 $matches[0]保存完整模式的所有匹配, $matches[1] 保存第一個子組的所有匹配,以此類推。
>> PREG_SET_ORDER
>>> 結果排序為 $matches[0] 包含第一次匹配得到的所有匹配(包含子組), $matches[1] 是包含第二次匹配到的所有匹配(包含子組)的數組,以此類推。
>> PREG_OFFSET_CAPTURE
>>> 匹配返回時會增加它相對目標字符串的偏移量。 注意這會改變matches中的每一個匹配結果字符串元素,使其 成為一個第0個元素為匹配結果字符串,第1個元素為 匹配結果字符串在subject中的偏移量。
>> 如果沒有給定排序標記,假定設置為 PREG_PATTERN_ORDER 。
> $offset 搜索源字符串開始位置,默認從字符串開頭搜索
> 返回值
> 返回完整匹配次數(可能是0),或者如果發生錯誤返回 FALSE 。
* * * * *
>[info]示例一 PREG_PATTERN_ORDER 標記
~~~
<?php
preg_match_all ( "|<[^>]+>(.*)</[^>]+>|U" ,
"<b>example: </b><div align=left>this is a test</div>" ,
$out , PREG_PATTERN_ORDER );
echo $out [ 0 ][ 0 ] . ", " . $out [ 0 ][ 1 ] . "\n" ;
echo $out [ 1 ][ 0 ] . ", " . $out [ 1 ][ 1 ] . "\n" ;
?>
~~~
輸出:
~~~
<b>example: </b>, <div align=left>this is a test</div>
example: , this is a test
~~~
>[info] $out[0] 是包含匹配完整模式的字符串的數組,
>$out[1] 是包含閉合標簽內的字符串的數組。
* * * * *
>[info]示例二 PREG_SET_ORDER 標記
~~~
<?php
preg_match_all ( "|<[^>]+>(.*)</[^>]+>|U" ,
"<b>example: </b><div align=\"left\">this is a test</div>" ,
$out , PREG_SET_ORDER );
echo $out [ 0 ][ 0 ] . ", " . $out [ 0 ][ 1 ] . "\n" ;
echo $out [ 1 ][ 0 ] . ", " . $out [ 1 ][ 1 ] . "\n" ;
?>
~~~
輸出:
~~~
<b>example: </b>, example:
<div align="left">this is a test</div>, this is a test
~~~
>[info]示例三 查找所有文本中的電話號碼。
~~~
<?php
preg_match_all ( "/\(? (\d{3})? \)? (?(1) [\-\s] ) \d{3}-\d{4}/x" ,
"Call 555-1212 or 1-800-555-1212" , $phones );
?>
~~~
>[info]示例四 查找匹配的HTML標簽(貪婪)
~~~
<?php
//\\2是一個后向引用的示例. 這會告訴pcre它必須匹配正則表達式中第二個圓括號(這里是([\w]+))
//匹配到的結果. 這里使用兩個反斜線是因為這里使用了雙引號.
$html = "<b>bold text</b><a href=howdy.html>click me</a>" ;
preg_match_all ( "/(<([\w]+)[^>]*>)(.*?)(<\/\\2>)/" , $html , $matches , PREG_SET_ORDER );
foreach ( $matches as $val ) {
echo "matched: " . $val [ 0 ] . "\n" ;
echo "part 1: " . $val [ 1 ] . "\n" ;
echo "part 2: " . $val [ 2 ] . "\n" ;
echo "part 3: " . $val [ 3 ] . "\n" ;
echo "part 4: " . $val [ 4 ] . "\n\n" ;
}
?>
~~~
輸出:
~~~
matched: <b>bold text</b>
part 1: <b>
part 2: b
part 3: bold text
part 4: </b>matched: <a href=howdy.html>click me</a>
part 1: <a href=howdy.html>
part 2: a
part 3: click me
part 4: </a>
~~~
>[info]示例五 使用子命名組
~~~
<?php
$str = <<<FOO
a: 1
b: 2
c: 3
FOO;
preg_match_all ( '/(?P<name>\w+): (?P<digit>\d+)/' , $str , $matches );
/* 下面代碼在php 5.2.2(pcre 7.0)或更高版本下工作, 不過, 為了向后兼容
* 推薦使用上面的方式. */
// preg_match_all('/(?<name>\w+): (?<digit>\d+)/', $str, $matches);
print_r ( $matches );
?>
~~~
輸出:
~~~
Array
(
[0] => Array
(
[0] => a: 1
[1] => b: 2
[2] => c: 3
) [name] => Array
(
[0] => a
[1] => b
[2] => c
) [1] => Array
(
[0] => a
[1] => b
[2] => c
) [digit] => Array
(
[0] => 1
[1] => 2
[2] => 3
) [2] => Array
(
[0] => 1
[1] => 2
[2] => 3
))
~~~
### 3 源字符串使用正則表達式分隔preg_split()
~~~
array preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] )
~~~
> $pattern:結果字符串正則描述
> $subject:源字符串
> $limit: 限制分割得到字符串個數,最后一個包含所有剩余部分
> -1,0,null代表不限制,
> $flags: 匹配狀態標記
> PREG_SPLIT_NO_EMPTY
> 返回分隔后的非空部分。
> PREG_SPLIT_DELIM_CAPTURE
> 返回用于分隔的模式中的括號表達式將被捕獲
> PREG_SPLIT_OFFSET_CAPTURE
> 對于每一個出現的匹配返回時將會附加字符串偏移量
> 每個元素成為一個由第0 個元素為分隔后的子串,第1個元素為該子串在subject 中的偏移量組成的數組
> 返回值
> 返回一個使用 pattern 邊界分隔 subject 后得到 的子串組成的數組。
* * * * *
>[info] 示例一 獲取搜索字符串的部分
~~~
<?php
//使用逗號或空格(包含" ", \r, \t, \n, \f)分隔短語
$keywords = preg_split ( "/[\s,]+/" , "hypertext language, programming" );
print_r ( $keywords );
?>
~~~
輸出:
~~~
Array
(
[0] => hypertext
[1] => language
[2] => programming
)
~~~
>[info] 示例二 將一個字符串分隔為組成它的字符
~~~
<?php
$str = 'string' ;
$chars = preg_split ( '//' , $str , - 1 , PREG_SPLIT_NO_EMPTY );
print_r ( $chars );
?>
~~~
以上例程會輸出:
~~~
Array
(
[0] => s
[1] => t
[2] => r
[3] => i
[4] => n
[5] => g
)
~~~
>[info] 示例三 分隔一個字符串并獲取每部分的偏移量
~~~
<?php
$str = 'hypertext language programming' ;
$chars = preg_split ( '/ /' , $str , - 1 , PREG_SPLIT_OFFSET_CAPTURE );
print_r ( $chars );
?>
~~~
輸出:
~~~
Array
(
[0] => Array
(
[0] => hypertext
[1] => 0
) [1] => Array
(
[0] => language
[1] => 10
) [2] => Array
(
[0] => programming
[1] => 19
))
~~~
### 4 源字符串搜索和替換 preg_replace()
~~~
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
~~~
> $pattern: 結果字符串正則描述 字符串或數組
> $replacement: 替換的字符串 字符串或數組
> 1 $pattern字符串,$replacement字符串:對應替換
> 2 $pattern數組,$replacement字符串:都使用本字符串替換
> 3 $pattern數組,$replacement數組
> 數組長度相等 對應替換
> 前者大于后者 多余使用空字符串替換
> 4 $replacement可以包含后向引用$n(也可以使用\\n)
> 后向引用見下文介紹
> $subject: 源字符串 字符串或數組
> $subject數組,在$subject的每一個元素上進行,返回值是替換結果組成的數組
> $limit: 替換最大次數 默認為-1 無限
> $count: 保存替換的完成次數
> 返回值
>> 如果subject是一個數組, preg_replace() 返回一個數組,
其他情況下返回一個字符串。
>> 如果匹配被查找到,替換后的subject被返回,
其他情況下 返回沒有改變的 subject。如果發生錯誤,返回 NULL 。
* * * * *
>[info] 示例一 使用后向引用緊跟數值原文
~~~
<?php
$string = 'April 15, 2003' ;
$pattern = '/(\w+) (\d+), (\d+)/i' ;
$replacement = '${1}1,$3' ;
echo preg_replace ( $pattern , $replacement , $string );
?>
~~~
輸出
`April1,2003`
>[info] 示例二 preg_replace() 中使用基于索引的數組
~~~
<?php
$string = 'The quick brown fox jumped over the lazy dog.' ;
$patterns = array();
$patterns [ 0 ] = '/quick/' ;
$patterns [ 1 ] = '/brown/' ;
$patterns [ 2 ] = '/fox/' ;
$replacements = array();
$replacements [ 2 ] = 'bear' ;
$replacements [ 1 ] = 'black' ;
$replacements [ 0 ] = 'slow' ;
echo preg_replace ( $patterns , $replacements , $string );
?>
~~~
輸出
`The bear black slow jumped over the lazy dog.`
>[info] 示例三 替換一些值
~~~
<?php
$patterns = array ( '/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/' ,
'/^\s*{(\w+)}\s*=/' );
$replace = array ( '\3/\4/\1\2' , '$\1 =' );
echo preg_replace ( $patterns , $replace , '{startDate} = 1999-5-27' );
?>
~~~
輸出:
`$startDate = 5/27/1999`
>[info] 示例四 剝離空白字符
~~~
<?php
$str = 'foo o' ;
$str = preg_replace ( '/\s\s+/' , ' ' , $str );
// 將會改變為'foo o'
echo $str ;
?>
~~~
> 這個例子剝離多余的空白字符
* * * * *
>[info] 示例五 使用參數count
~~~
<?php
$count = 0 ;
echo preg_replace (array( '/\d/' , '/\s/' ), '*' , 'xp 4 to' , - 1 , $count );
echo $count ; //3
?>
~~~
輸出:
~~~
xp***to
3
~~~
* * * * *
### 5 源字符串搜索和替換 preg_replace_callback()
~~~
mixed preg_replace_callback ( mixed $pattern , callable $callback , mixed $subject [, int $limit = -1 [, int &$count ]] )
~~~
> $pattern:同上
> $callback: 替換回調函數,參數是匹配結果數組
>> string handler ( array $matches )
>> 使用匿名函數作為 preg_replace_callback() 調用時的回調
> $subject:同上
> $limit:同上
> $count:同上
* * * * *
>[info] 示例一 preg_replace_callback() 示例
~~~
<?php
// 將文本中的年份增加一年.
$text = "April fools day is 04/01/2002\n" ;
$text .= "Last christmas was 12/24/2001\n" ;
// 回調函數
function next_year ( $matches )
{
// 通常: $matches[0]是完成的匹配
// $matches[1]是第一個捕獲子組的匹配
// 以此類推
return $matches [ 1 ].( $matches [ 2 ]+ 1 );
}
echo preg_replace_callback (
"|(\d{2}/\d{2}/)(\d{4})|" ,
"next_year" ,
$text );
?>
~~~
輸出:
~~~
April fools day is 04/01/2003
Last christmas was 12/24/2002
~~~
>[info] 示例二 preg_replace_callback() 使用遞歸構造處理BB碼的封裝
~~~
<?php
$input = "plain [indent] deep [indent] deeper [/indent] deep [/indent] plain" ;
function parseTagsRecursive ( $input )
{
/* 譯注: 對此正則表達式分段分析
* 首尾兩個#是正則分隔符
* \[indent] 匹配一個原文的[indent]
* ((?:[^[]|\[(?!/?indent])|(?R))+)分析:
* (?:[^[]|\[(?!/?indent])分析:
* 首先它是一個非捕獲子組
* 兩個可選路徑, 一個是非[字符, 另一個是[字符但后面緊跟著不是/indent或indent.
* (?R) 正則表達式遞歸
* \[/indent] 匹配結束的[/indent]
* /
$regex = '#\[indent]((?:[^[]|\[(?!/?indent])|(?R))+)\[/indent]#';
if (is_array($input)) {
$input = '<div style="margin-left: 10px">'.$input[1].'</div>';
}
return preg_replace_callback($regex, 'parseTagsRecursive', $input);
}
$output = parseTagsRecursive($input);
echo $output;
?>
~~~
### 6 源字符串搜索和替換 preg_filter()
### 7 轉義正則表達式 preg_quote()
### 8 返回匹配模式的數組條目 preg_grep()
### 9 查找正則執行的最后一個錯誤 preg_last_error()
## 3 正則表達式規則詳解
### 3-1 語法概述
正則表達式可以看做一種**語法經過壓縮的程序語言**
因此從程序語言的角度看待正則表達式,
* * * * *
#### 3-1-1正則界定符
>[info] 1 正則表達式使用一組字符串表示界定符,
正則表達式與php使用`<?php` `?>`作為界定符原理相同,
正則表達式使用界定符包圍正則字符串作為正則代碼。
經常遇到界定符包括**正斜線(/)、hash符號(#) 以及取反符號(~) 括號() {} []**
~~~
/foo bar/ ; "/"界定符
#^[^0-9]$# ; "#"界定符
+php+ ; "+"界定符
%[a-zA-Z0-9_-]% ; "%"界定符
~~~
正則表達式中需要匹配界定符時 使用反斜線進行轉義
~~~
/http:\/\// ;"/"作為界定符,匹配http://時,"/"需要轉義
#http://# ;"#"作為界定符,匹配http://時,"/"不需要轉義
~~~
>[info]2 可以用 preg_quote()函數對其進行轉義
>[info]3 可以在結束分隔符后面增加模式修飾符。
* * * * *
#### 3-1-2語法組成
正則表達式中的語法可以分為**數據結構與邏輯控制**
**數據結構包括:**
>[info] 1 常量字符串:普通字符組成
> 2 變量字符串, 特殊字符組成
**邏輯控制包括:**
>[info] 1 變量字符串獲取,變量字符串賦值,
> 2 匹配位置控制,邏輯if判斷,邏輯for循環,邏輯或判斷
### 3-2 正則表達式數據結構
#### 3-2-1 常量字符串
**常量字符串通常用來精確匹配字符串組成。**
>[info] 1 匹配常量字符串hello
~~~
<?php
application/index/controller/Index.php
public function hello(){
$str='hello world';
$pattern='/hello/';
preg_match($pattern,$str,$matches);
dump($matches);
}
?>
~~~
輸出
~~~
http://127.0.0.1/tp5/public/index.php/Index/Index/hello
array(1) {
[0] => string(5) "hello"
}
~~~
>[info] 2 匹配忽略大小寫常量字符串hello
~~~
<?php
application/index/controller/Index.php
public function hello(){
$str='Hello world';
$pattern='/hello/i';
preg_match($pattern,$str,$matches);
dump($matches);
}
?>
~~~
輸出
~~~
http://127.0.0.1/tp5/public/index.php/Index/Index/hello
array(1) {
[0] => string(5) "Hello"
}
~~~
#### 3-2-2 變量字符串
**變量字符串使用正則表達式中的特殊字符模糊匹配字符串**
>[info] 1 變量字符串元素
變量字符串使用正則表達式的**特殊字符組成**
這里的特殊字符串可以看做**程序語言的數據類型**概念
根據其組成的復雜度分為**簡單變量字符,字符類變量字符**
簡單變量字符 使用**單個特殊元字符**表示
字符類變量字符 使用**帶有方括號[]聲明格式**表示
>[info] 2 簡單變量字符
~~~
\d ;匹配一個數字字符 等價于[0-9]
\D ;匹配一個非數字字符 等價于[^0-9]
\s ;匹配一個任意空白字符 等價于[\n\r\t\v\f]
\S ;匹配一個任意非空白字符 等價于[^\n\r\t\v\f]
\w ;匹配一個字母/數字/下劃線/漢字字符 等價于[A-Za-z0-9_]
\W ;匹配一個任意非單詞字符 等價于[^A-Za-z0-9_]
. ;匹配一個 除換行\n外的任意字符 等價于[^\n]
~~~
~~~
\n ;匹配一個換行符 等價于\x0a和\cL
\r ;匹配一個回車符 等價于\x0d和\cM
\t ;匹配一個水平制表符 等價于\x09和\cI
\v ;匹配一個垂直制表符 等價于\x0b和\cK
\f ;匹配一個換頁符 等價于\x0c和\cL
~~~
~~~
<?php
application/index/controller/Index.php
public function hello(){
$str='<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微軟雅黑"; color: #333;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>歡迎使用 <b>ThinkPHP5</b>!</p></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>';
// 數字字符
$pattern1='/\d/';
preg_match($pattern1,$str,$matches1);
dump($matches1);
// 空白字符
$pattern2='/\s/';
preg_match($pattern2,$str,$matches2);
dump($matches2);
//字符/數字/下劃線/漢字字符
$pattern3='/\w/';
preg_match($pattern3,$str,$matches3);
dump($matches3);
}
?>
~~~
輸出
~~~
http://127.0.0.1/tp5/public/index.php/Index/Index/hello
array(1) {
[0] => string(1) "0"
}
array(1) {
[0] => string(1) " "
}
array(1) {
[0] => string(1) "s"
}
~~~
>[info] 3 字符類變量字符
~~~
[xyz] ;匹配xyz其中一個字符
[a-z] ;匹配a到z其中一個字符
[A-Z] ;匹配A到Z其中一個字符
[0-9] ;匹配0到9其中一個字符
[^xyz] ;匹配除xyz以外的一個字符
[^a-z] ;匹配除a到z外的一個字符
~~~
~~~
<?php
application/index/controller/Index.php
public function hello(){
$str='<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微軟雅黑"; color: #333;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>歡迎使用 <b>ThinkPHP5</b>!</p></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>';
// x y z中一個
$pattern1='/[xyz]/';
preg_match($pattern1,$str,$matches1);
dump($matches1);
// a-z中一個
$pattern2='/[a-z]/';
preg_match($pattern2,$str,$matches2);
dump($matches2);
// A-Z中一個
$pattern3='/[A-Z]/';
preg_match($pattern3,$str,$matches3);
dump($matches3);
// 0-9中一個
$pattern4='/[0-9]/';
preg_match($pattern4,$str,$matches4);
dump($matches4);
}
?>
~~~
輸出:
~~~
http://127.0.0.1/tp5/public/index.php/Index/Index/hello
array(1) {
[0] => string(1) "y"
}
array(1) {
[0] => string(1) "s"
}
array(1) {
[0] => string(1) "T"
}
array(1) {
[0] => string(1) "0"
}
~~~
### 3 正則表達式邏輯控制
#### 3-3-1 匹配位置控制(^ $ \b)
~~~
^x ;匹配以x開頭的字符串
$x ;匹配以x結尾的字符串
\bxy\b ;匹配以x開頭y結尾的單詞
~~~
~~~
<?php
application/index/controller/Index.php
public function hello(){
$str='<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微軟雅黑"; color: #333;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>歡迎使用 <b>ThinkPHP5</b>!</p></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>';
// 是否已s開頭
$pattern1='/^a/';
preg_match($pattern1,$str,$matches1);
dump($matches1);
// 是否以a結尾
$pattern2='/a$/';
preg_match($pattern2,$str,$matches2);
dump($matches2);
// 以t開頭中間是字母的e結尾單詞
$pattern3='/\bt\w*e\b/';
preg_match($pattern3,$str,$matches3);
dump($matches3);
}
?>
~~~
輸出:
~~~
array(0) {
}
array(0) {
}
array(1) {
[0] => string(4) "type"
}
~~~
#### 3-3-2 匹配字符或控制(|)
~~~
x|y ;匹配x或y中一個字符
[a-z]|[A-Z] ;匹配a到z或A到Z中一個字符
~~~
#### 3-3-3 字符匹配獲取和賦值(()\1,()$1, (?<name>)<name>)
變量獲取:匹配分組()
>[info] 使用()可以獲取指定匹配內容到分組中
~~~
(exp) 匹配exp變量,并存儲到結果分組中
~~~
~~~
(\d) 匹配數字分組,并進行存儲
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?) 匹配多個分組,并進行存儲
~~~
變量賦值:反向引用\1 $1 <name>
>[info] 獲取分組后,可以使用反向引用進一步操作
> 可以使用\n或者$n的形式獲取對應分組內容(n從1開始)
> 也可以指定組名<Word>進行反向引用
~~~
\b(\w+)\b\s+\1\b
;使用\1對匹配內容(\w)進行反向引用
\b(?<Word>\w+)\b\s+\k<Word>\b
;使用<Word>對匹配內容進行反向引用
~~~
#### 3-3-4 字符前后if判斷 ((?=),(?!),(?<=),(?<!))
~~~
(?<=exp)x 匹配前面是exp的x (if x.prev == exp){匹配x}
(?<!exp)x 匹配前面不是exp的x (if x.prev != exp){匹配x}
x(?=exp) 匹配后面是exp的x (if x.next == exp){匹配x}
x(?!exp) 匹配后面不是exp的x (if x.next != exp){匹配x}
多個判斷組合
或判斷 (?<=bullock|donkey)x 匹配前面是bullock或者donkey的x
且判斷 (?<=\d{3})(?<!999)foo 匹配前面是3個數字而且不是999的foo
嵌套判斷 (?<=(?<!foo)bar)baz 嵌套判斷匹配前面有 ”bar” 但是 ”bar” 前面沒有 ”foo” 的 ”baz”。
嵌套判斷 (?<=\d{3}…(?<!999))foo 匹配前面有三個數字字符緊跟 3 個不是 999 的任意字符的 ”foo”。
~~~
#### 3-3-5 字符循環次數for循環 (*,+,?,{n,m})
~~~
x* ;匹配零或多次個x字符 for(i=0;i>=0;i++){匹配x*i}
x+ ;匹配一次或多次個x字符 for(i=0;i>0;i++){匹配x*i}
x? ;匹配零次或一次個x字符 for(i=0;0<=i<=1;i++){匹配x*i}
x{n} ;匹配n次個x字符 for(i=0;i==n;i++){匹配x*i}
x{n,} ;匹配n次或更多次個x字符 for(i=0;i>=n;i++){匹配x*i}
x{n,m} ;匹配n到m次個x字符 for(i=0;n<=x<=m;i++){匹配x*i}
~~~
#### 3-3-6 匹配模式修飾符
~~~
\i ;忽略大小寫
\m ;多行字符串檢測
\s ;.字符匹配包括換行符(\n)在內的所有字符
~~~
#### 3-3-7 子組高級控制
>[info] 1 命名性子組
(?<name>exp) 匹配exp變量,并存儲到名稱為name的結果分組中
* * * * *
>[info] 2 非捕獲性子組
(?:exp) 匹配exp變量,不進行存儲,
* * * * *
>[info] 3 一次性子組
(?>exp) 匹配exp變量,不對其內部進行匹配
使用\d+foo 匹配123456bar
當最長匹配6個數字后,匹配foo失敗時
正則解析器會嘗試匹配5個數字,再匹配foo,如果失敗
則依次嘗試4個數字,3個數字,2個數字等
為了第一次匹配失敗后,就停止匹配,可以使用一次性子組
(?>\d+)foo 匹配 123456bar
第一次匹配失敗時就返回false
* * * * *
>[info] 4 條件性子組
(?(conditon)yes-pattern|no-pattern)
**condtion為數字**, 該數字代表的(之前的)子組得到匹配時
使用yes-pattern,否則存在no-pattern使用no-pattern
~~~
( \( )? [^()]+ (?(1) \) )
~~~
**condtion為字符串** , 得到對模式或子模式的遞歸調用時滿足?
**condition是前后判斷**,判斷匹配成功
使用yes-pattern,否則存在no-pattern使用no-pattern
~~~
(?(?=[^a-z]*[a-z])\d{2}-[a-z]{3}-\d{2}|\d{2}-\d{2}-\d{2})
~~~
## 4 正則表達式示例分析
~~~
1 application\index\controller\Regextest.php
<?php
namespace app\index\controller;
class Regextest extends Controller
{
public function test()
{
$extend = $this->getRegex('extend');
$block = $this->getRegex('block');
$literal = $this->getRegex('literal');
$include = $this->getRegex('include');
$taglib = $this->getRegex('taglib');
$layout = $this->getRegex('layout');
$tag = $this->getRegex('tag');
dump($extend);
dump($block);
dump($literal);
dump($include);
dump($taglib );
dump($layout);
dump($tag);
}
private function getRegex($tagName)
{
$begin = '{';
$end = '}';
$single = strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1 ? true : false;
$regex = '';
switch ($tagName) {
case 'block':
if ($single) {
$regex = $begin . '(?:' . $tagName . '\b(?>(?:(?!name=).)*)\bname=([\'\"])(?<name>[\w\/\:@,]+)\\1(?>[^' . $end . ']*)|\/' . $tagName . ')' . $end;
} else {
$regex = $begin . '(?:' . $tagName . '\b(?>(?:(?!name=).)*)\bname=([\'\"])(?<name>[\w\/\:@,]+)\\1(?>(?:(?!' . $end . ').)*)|\/' . $tagName . ')' . $end;
}
break;
case 'literal':
if ($single) {
$regex = '(' . $begin . $tagName . '\b(?>[^' . $end . ']*)' . $end . ')';
$regex .= '(?:(?>[^' . $begin . ']*)(?>(?!' . $begin . '(?>' . $tagName . '\b[^' . $end . ']*|\/' . $tagName . ')' . $end . ')' . $begin . '[^' . $begin . ']*)*)';
$regex .= '(' . $begin . '\/' . $tagName . $end . ')';
} else {
$regex = '(' . $begin . $tagName . '\b(?>(?:(?!' . $end . ').)*)' . $end . ')';
$regex .= '(?:(?>(?:(?!' . $begin . ').)*)(?>(?!' . $begin . '(?>' . $tagName . '\b(?>(?:(?!' . $end . ').)*)|\/' . $tagName . ')' . $end . ')' . $begin . '(?>(?:(?!' . $begin . ').)*))*)';
$regex .= '(' . $begin . '\/' . $tagName . $end . ')';
}
break;
case 'restoreliteral':
$regex = '<!--###literal(\d+)###-->';
break;
case 'include':
$name = 'file';
case 'taglib':
case 'layout':
case 'extend':
if (empty($name)) {
$name = 'name';
}
if ($single) {
$regex = $begin . $tagName . '\b(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?<name>[\$\w\-\/\.\:@,\\\\]+)\\1(?>[^' . $end . ']*)' . $end;
} else {
$regex = $begin . $tagName . '\b(?>(?:(?!' . $name . '=).)*)\b' . $name . '=([\'\"])(?<name>[\$\w\-\/\.\:@,\\\\]+)\\1(?>(?:(?!' . $end . ').)*)' . $end;
}
break;
case 'tag':
$begin = '{';
$end = '}';
if (strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1) {
$regex = $begin . '((?:[\$]{1,2}[a-wA-w_]|[\:\~][\$a-wA-w_]|[+]{2}[\$][a-wA-w_]|[-]{2}[\$][a-wA-w_]|\/[\*\/])(?>[^' . $end . ']*))' . $end;
} else {
$regex = $begin . '((?:[\$]{1,2}[a-wA-w_]|[\:\~][\$a-wA-w_]|[+]{2}[\$][a-wA-w_]|[-]{2}[\$][a-wA-w_]|\/[\*\/])(?>(?:(?!' . $end . ').)*))' . $end;
}
break;
}
return '/' . $regex . '/is';
}
}
~~~
輸出:
~~~
string(86) "/{extend\b(?>(?:(?!name=).)*)\bname=([\'\"])(?<name>[\$\w\-\/\.\:@,\\]+)\1(?>[^}]*)}/is"
string(89) "/{(?:block\b(?>(?:(?!name=).)*)\bname=([\'\"])(?<name>[\w\/\:@,]+)\1(?>[^}]*)|\/block)}/is"
string(97) "/({literal\b(?>[^}]*)})(?:(?>[^{]*)(?>(?!{(?>literal\b[^}]*|\/literal)}){[^{]*)*)({\/literal})/is"
string(87) "/{include\b(?>(?:(?!file=).)*)\bfile=([\'\"])(?<name>[\$\w\-\/\.\:@,\\]+)\1(?>[^}]*)}/is"
string(86) "/{taglib\b(?>(?:(?!name=).)*)\bname=([\'\"])(?<name>[\$\w\-\/\.\:@,\\]+)\1(?>[^}]*)}/is"
string(86) "/{layout\b(?>(?:(?!name=).)*)\bname=([\'\"])(?<name>[\$\w\-\/\.\:@,\\]+)\1(?>[^}]*)}/is"
~~~
對于extend正則分解如下
~~~
/{ ;開始標簽{
extend\b 以extend開始的單詞匹配
(?> ; ?> 子組一次性匹配聲明
(?: ; ?: 子組不捕獲匹配聲明
(?!name=). ; 后面不是name=的任意字符.
)* ;任意字符數量為零或多個
)\b ;以上述字符為結束
name= ;匹配name=
([\'\"]) ;匹配單引號或者雙引號子組
(?<name> ;命名子組name聲明
[\w\/\:@,]+ ;雙引號中的字符串組成
)
\\1 ;匹配的單引號或者雙引號子組
(?>
(?> ;子組一次性匹配聲明
[^}]* ;非}的零或多個字符
) ;這個做什么?
}/ ;結束標簽}
~~~
- 更新記錄
- 概述
- 文件索引
- 函數索引
- 章節格式
- 框架流程
- 前:章節說明
- 主:(index.php)入口
- 主:(start.php)框架引導
- 主:(App.php)應用啟動
- 主:(App.php)應用調度
- C:(Controller.php)應用控制器
- M:(Model.php)數據模型
- V:(View.php)視圖對象
- 附:(App.php)應用啟動
- 附:(base.php)全局變量
- 附:(common.php)模式配置
- 附:(convention.php)全局配置
- 附:(Loader.php)自動加載器
- 附:(Build.php)自動生成
- 附:(Hook.php)監聽回調
- 附:(Route.php)全局路由
- 附:(Response.php)數據輸出
- 附:(Log.php)日志記錄
- 附:(Exception.php)異常處理
- 框架工具
- 另:(helper.php)輔助函數
- 另:(Cache.php)數據緩存
- 另:(Cookie.php)cookie操作
- 另:(Console.php)控制臺
- 另:(Debug.php)開發調試
- 另:(Error.php)錯誤處理
- 另:(Url.php)Url操作文件
- 另:(Loader.php)加載器實例化
- 另:(Input.php)數據輸入
- 另:(Lang.php)語言包管理
- 另:(ORM.php)ORM基類
- 另:(Process.php)進程管理
- 另:(Session.php)session操作
- 另:(Template.php)模板解析
- 框架驅動
- D:(\config)配置解析
- D:(\controller)控制器擴展
- D:(\model)模型擴展
- D:(\db)數據庫驅動
- D:(\view)模板解析
- D:(\template)模板標簽庫
- D:(\session)session驅動
- D:(\cache)緩存驅動
- D:(\console)控制臺
- D:(\process)進程擴展
- T:(\traits)Trait目錄
- D:(\exception)異常實現
- D:(\log)日志驅動
- 使用范例
- 服務器與框架的安裝
- 控制器操作
- 數據模型操作
- 視圖渲染控制
- MVC開發初探
- 模塊開發
- 入口文件定義全局變量
- 運行模式開發
- 框架配置
- 自動生成應用
- 事件與插件注冊
- 路由規則注冊
- 輸出控制
- 多種應用組織
- 綜合應用
- tp框架整合后臺auto架構快速開發
- 基礎原理
- php默認全局變量
- php的魔術方法
- php命名空間
- php的自動加載
- php的composer
- php的反射
- php的trait機制
- php設計模式
- php的系統時區
- php的異常錯誤
- php的輸出控制
- php的正則表達式
- php的閉包函數
- php的會話控制
- php的接口
- php的PDO
- php的字符串操作
- php的curl
- 框架心得
- 心:整體結構
- 心:配置詳解
- 心:加載器詳解
- 心:輸入輸出詳解
- 心:url路由詳解
- 心:模板詳解
- 心:模型詳解
- 心:日志詳解
- 心:緩存詳解
- 心:控制臺詳解
- 框架更新
- 4.20(驗證類,助手函數)
- 4.27(新模型Model功能)
- 5.4(新數據庫驅動)
- 7.28(自動加載)