/ PHP

[PHP note.] 關於正規表示式的一點筆記

我發現我很久沒有寫 PHP 的筆記了,不過因為我本來就不太會寫 PHP,所以文章很少也是很合理的(挺)。這次要筆記的東西是正規表示式,其實網路上文章非常多,我首推這篇:Regular Expression (RegExp) in JavaScript

疑?怎麼是 Javascript!?哎呀,沒關係啦,其實正規表示式大家都差不多嘛(喂)。但是呢,我這裡筆記的東西請不要直接搬去給 Javascript 用,會出人命的。首先,我要講得東西這邊全部都有:

PCRE regex syntax

所以如果英文不錯的人可以直接看官方說明就好。我這裡只是因為英文很爛所以筆記一下而已(無責)。比較基礎就不再贅述了,去問 Google 大神應該可以找到一大堆,倒是,這一篇官方說明可以筆記一下,有一些跳脫的字元可以留意一下,免得誤觸地雷。

Escape sequences

至於 Internal option setting 也請記得,不要誤用。請注意 PCRE_MULTILINE/^(.*)$/m)的設定,他會讓你的定位結果(使用 ^$ 時)與其他的設定不同。而,這個設定也可以在 Subpatterns 中使用,使用的方法大概是這樣:(?i: 或是 (?m<= 爾等。

接著來提一下 Subpatterns 的作法。在正規表示式中,我們可以依照提取出來的結果,更準確的把我們想要的部份個切割開來。這種時候 Subpatterns 就異常的好用。首先先說明一下我們有哪些工具可用:

  • ( ) 最常見的括號,代表將內容做一個記憶群組動作。
  • (?: ) 與括號作用相同,不同的是,這個群組是不會被記憶的。
  • (?| ) 當群組使用多選時,可以避免沒有選中結果,但卻產生空的群組(該群組還會被記憶)。
  • (?<name> ) 群組命名,一般正規輸出都是單純陣列,這個命名會是陣列鍵值。

另外還有比較特殊的用法,稱為右(左)合右(左)不合的形式,可搭配條件比對使用:

  • (?= 左合樣式
  • (?<= 右合樣式
  • (?! 左不合樣式
  • (?<! 右不合樣式

另外也是特殊用法之一,單次比對(Once-only subpattern):

  • `(?> 顧名思義就是,我只比對一次。

還有條件式比對(Conditional subpattern),請搭配左(右)合(不合)樣使用:

  • `(?(condition)yes-pattern) 照字面上的意思,就不用多做解釋了吧。
  • `(?(condition)yes-pattern|no-pattern) 同上,只是多了個 no-pattern 而已(喂

然後,既然有群組(不管是否有記憶動作),就能夠拿出來參考(Back references):

  • \1 常見用法,將第一個群組拿出來用。
  • \g1, \g1, \g{1}, \g{-1} 取出特定群組用法,用大括號有一個特別的地方就是,可以避免一些問題*****。
  • (?P=name) 遇到有命名的群組,這樣可以把該群組拿出來用。

舉一個例子,我用顏色區隔應該會比較好理解一點(有嗎?):

"/(?:(?P(?|_t|_f|_text|_textf))((?P(?|'|")))(?P[^'"]*)?/i"

這是我用來掃描原始碼,當其中有 _t('xxxxx') 或是 _text("xxxxx") 出現時,把 _t 這類的程式名稱命名為 tag,把 ' 或是 " 命名為 quote,然後把程式包的內容命名為 content,其中 content 的內容是非第一記憶群組的所有文字。抓出來就是我要的結果嗎?

假設變數是這樣:

$a = '_t("123") _f(\'456\') _text(\'789 "12345" 6789\')';

其實結果並不如預期,無論在單行或是多行處理時,最後一個條件會符合這種情況:

_t('123
_f('456
_text('789 // 這裡出現斷尾了!

如何避免?其實我也不知道,早跟你說我不太會寫 PHP 了。

斷尾問題就留給大家了(誒?!

* 官方文件中提到:

The use of this pattern with an unsigned number can help remove the ambiguity inherent when using digits following a backslash. The sequence helps to distinguish back references from octal characters and also makes it easier to have a back reference followed by a literal number, e.g. \g{2}1.