[PHP note.] 正規表示式順序筆記

關於一些正規筆記 請參考前一篇。這裡直接從範例開始解析正規的順序:

範例字串:

$a = "_func1('abcdef') xxxx _func2('abcdefghijkl') xxxx _func1('1234567890') xxxx";

正規表示式:

/(?P<tag>(?|_func1|_func2))\((?P<quote>(?|'|\"))(?P<content>[^'\"]*)/i
```

看起來很複雜,實際上正規表示式的運作模式大抵上可以這樣解釋:

1. 先做全域比對(這是在 PHP 使用 preg\_match 系列時會這麼做)。
* 再做群組區塊比對,比對區塊 1。
* 比對區塊 2。
* 依此類推。

所以第一次比對時,會比對整條正規表示式:

```
(?P<tag>(?|_func1|func2))\((?P<quote>(?|'|\"))(?P<content>[^'\"]*)
```

所得到的結果會是:

```
[0] => Array (
  [0] => \_func1('abcdef
  [1] => \_func2('abcdefghijkl
  [2] => \_func1('1234567890
)
```

接著比對第一個群組:

```
(?P<tag>(?|_func1|func2))
```

所得到的結果會是:

```
[tag] => Array (
  [0] => \_func1
  [1] => \_func2
  [2] => \_func1
)
[1] => (
  [0] => \_func1
  [1] => \_func2
  [2] => \_func1
)
```

再來繼續比對第二個群組:

```
(?P<quote>(?|'|\"))
```

所得到的結果是:

```
[quote] => Array (
  [0] => '
  [1] => '
  [2] => '
)
[2] => Array ( 
  [0] => '
  [1] => '
  [2] => '
)
```

最後比對第三個群組:

```
(?P<content>[^'\"]*)
```

所得到的結果是:

```
[content] => Array (
  [0] => abcdef
  [1] => abcdefghijkl
  [2] => 1234567890
)
[3] => Array ( 
  [0] => abcdef
  [1] => abcdefghijkl
  [2] => 1234567890
)
```

要注意的地方有:

* 請勿在一開始就使用左(右)合(不合)樣式,除非你很清楚你要做什麼。
* 第一次比對若無符合項目,則往後的比對都會直接中斷。
* 比對的順序是由左至右,判斷式與左(右)合(不合)樣式有些例外。

使用 **右不合樣式** 的範例,我們給一個字串:

```
$a = "123123 456456 789789  123000 456000 789000";
```

使用正規表示式:
```
(?>[0-9]{6})(?<![123])/
```

產生結果為:

```
[0] => Array (
  [0] => 456456
  [1] => 789789
  [2] => 123000
  [3] => 456000
  [4] => 789000
)
```

這個正規在做的事情,大致上是這樣:

1. 我要 0~9 的六碼數字。
* <span style="color:#177fcd;">並且這些數字不會是有包含 123 為右方結尾的字串</font>。

何謂 **右不合**?

意思就是,當我字串符合條件時,從右邊往左比對的結果是不是符合我所需要的判斷。同樣的,左不合的意思就是從左邊往右邊比對的結果,但是,這兩個正規放的地方並不太一樣,底下是 **左不合** 的案例:

使用正規表示式:

```
(?![123])(?>[0-9]{6})
```

產生的結果是:

```
[0] => Array (
  [0] => 456456
  [1] => 789789
  [2] => 456000
  [3] => 789000
)  
```

這樣看出差異性了嗎?所以,如果要使用判斷式(`(?( ) )` 樣)的話,請先想好你的判斷條件,左(右)合(不合)樣所放置的位置是不一樣的。所以,我們在上一篇的截斷問題,就可以用判斷式來解決。

留個引子吧。

##/(?:(?|_func1|_func2))\(<span style="color:#d41a01;">(?</span><span style="color:#008000;">(?=['])</span><span style="color:#177fcd;">(?:'([^']*))</span><span style="color:#d41a01;">|</span><span style="color:#ff3399;">(?:\"([^\"]*))</span><span style="color:#d41a01;">)</span>/

留意有顏色的地方就好了。我沒有加上群組命名,所以比較乾淨,這樣應該很容易就能看懂了。

祝各位在正規的地獄中得道昇天!
Hina Chen
偏執與強迫症的患者,算不上是無可救藥,只是我已經遇上我的良醫了。
Taipei