2012年8月2日 星期四

PHP的正規表示式(Regular Expression)

要用正規表示式時,常常忘記符號的用法,所以整理了以下幾個表,將常用的正規式符號意義列出來。

特殊字元表示法
表示法 說明 ASCII
\a alert x07
\b backspace x08
\e ESC x1B
\n newline x0A
\r 回列首(Carriage Return) x0D
\f 換頁(Form Feed) x0C
\t tab x09
\octal octal為三位數的8進位數字
\xhex hex 為一位或二位的16進位數字
\x{hex} hex 為任何有效的16進位數字

PHP的Character Classes (Character Sets)
Character 說明
[...] 在列舉的範圍內
[^...] 不在列舉的範圍內
[:class:] POSIX的字元類組(POSIX character classes)
. 任何字元,\n 除外(除非在 /s 單列模式下)
\C 單一位元組。(Unicode有問題?)
\w 字詞字元。即 [a-zA-Z0-9_]
\W 非字詞字元。即 [^a-zA-Z0-9_]
\d 數字。即 [0-9]
\D 非數字。即 [^0-9]
\s 空白字元。即[\n\r\f\t ]
\S 非空白字元。即[^\n\r\f\t ]

Anchoring Metacharacters
Character 說明
^ 字串開頭
或每一行開頭(任何 \n 之後)(在 /m 多列模式下)。
$ 字串結尾
或每一行結尾(任何 \n 之前)(在 /m 多列模式下)。
\Z 字串結尾或每一行結尾(任何 \n 之前)
不管哪一種模式。
\A 只比對字串開頭。
不管哪一種模式。
\z 字串結尾
不管哪一種模式。
\G 目前的比對起點
\b word boundary,介於 \w 與 \W 之間位置,以及字串開頭與結尾。
\B 非word boundary
(?=...) Positive lookahead
(?!...) Negative lookahead
(?<=...) Positive lookbehead
(?<!...) Negative lookbehead

Pattern Modifiers
http://php.net/manual/en/reference.pcre.pattern.modifiers.php
modifiers 說明
i 不區分大小寫
m 多列模式
s 單列模式
x 忽略空白字元,允許出現「#..」註解
U 反轉貪多(greedy)性質,「*」變成不貪多,「*?」變成貪多。
A 強制從字串起點開始比對
D 強制「$」代表字串結尾,而非「\n」之前的位置。
(m多列模式效力大於此模式)
u 將正規式與受測字串都視為UTF8
(?mode) 以指定的 mode 比對後續樣式。mode 為 imsxU 有效組合。
(?-mode) 取消 mode 對後續樣式的影響。mode 為 imsxU 有效組合。
(?mode:...) 以指定的 mode 比對括弧內的樣式。mode 為 imsx 有效組合。
(?-mode:...) 取消 mode 對括弧內樣式的影響。mode 為 imsx 有效組合。

其他
語法 說明
\Q...\E \Q 到 \E 中間所有中介符號都視為一般字元。
(?#...) 將子字串視為註解
#... x 模式下,# 到列尾視為註解
(...) 子樣式,並將符合子樣式的字串儲存於 \1、\2...變數
\n 符合第 n 組子樣式的字串。
(?P<name>...) 子樣式,並將符合子樣式的字串儲存於 \name 變數
\name 符合名稱為 name 子樣式的字串。
(?:...) 子樣式,但不儲存於 \1、\2...變數
(?>...) 禁止符合字串被回步
...|... OR
* 0次以上 (貪多)
範例:
原字串:abbbcc
正規式:ab*
結果:abbb (貪多,以多為優先)
+ 1次以上
? 0次或1次
{n} 剛好n次
{n,} n次以上
{x,y} x次~y次
*? 0次或多次,以少為優先
範例:
原字串:abbbcc
正規式:ab*?
結果:a (不貪多,以少為優先)
+? 1次或多次,以少為優先
?? 0次或1次,以少為優先
{n,}? n次以上,以少為優先
{x,y}? x次~y次,以少為優先
*+ 0次或多次,不回步(backtracking)
++ 1次或多次,不回步
?+ 0次或1次,不回步
{n}+ 剛好n次,不回步
{n,}+ n次以上,不回步
{x,y}+ x次~y次,不回步
(?(condition)...|...) if-then-else。
condition:子樣式儲存邊號、lookahead、lookbehind
(?(condition)...) if-then。
condition:子樣式儲存邊號、lookahead、lookbehind

範例1:
$str = "/ABC/20151201/123456.txt";
if (1 !== preg_match('/^\/.+\/([\d]{4})([\d]{2})([\d]{2})\//', $str, $matches)) {
    throw new \Exception("分析失敗");
}
var_dump($matches); 
結果
rray(4) {
  [0]=>
  string(14) "/ABC/20151201/"
  [1]=>
  string(4) "2015"
  [2]=>
  string(2) "12"
  [3]=>
  string(2) "01"
}


範例2:
找出英文數字中,同一個字元,重複3次以上的資料
$str = "ggffffffasd1222233GGGfHHHH";
preg_match_all("/([a-zA-Z0-9])\\1{2,}/", $str, $matches);
var_dump($matches); 
結果
array(2) {
  [0]=>
  array(4) {
    [0]=>
    string(6) "ffffff"
    [1]=>
    string(4) "2222"
    [2]=>
    string(3) "GGG"
    [3]=>
    string(4) "HHHH"
  }
  [1]=>
  array(4) {
    [0]=>
    string(1) "f"
    [1]=>
    string(1) "2"
    [2]=>
    string(1) "G"
    [3]=>
    string(1) "H"
  }
}


範例3:
將英文數字同一個字元重複3次以上的地方,取代為只留一個字元
$str = "ggffffffasd1222233GGGfHHHH";
$res = preg_replace('/([a-zA-Z0-9])\\1{2,}/', '$1', $str);
var_dump($res);
結果
string(13) "ggfasd1233GfH"


參考:
http://www.php.net/manual/en/book.pcre.php
http://www.php.net/manual/en/reference.pcre.pattern.syntax.php
http://www.regular-expressions.info/reference.html 
RegexOne - Learn Regular Expressions - PHP

1 則留言: