Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
今天在幫同事處理一個公司網站的規則運算式 (regular expression) 問題:我用 ACF 客製化的區塊沒辦法正確產生項目符號。
正常的情況應該是這樣:
但是我同事在寫文章的時候變成這樣:
後來上 Regex 101 實驗之後,才發現是自己的規則運算式有問題。原本用來比對的規則運算式如下:
if ( preg_match( '/(\w+)<br\s*\/*>/', $content ) ) { // 將換行標籤 <br /> 與 <br> 取代為 </li><li>,作為項目符號。 $content = '<ul><li>' . preg_replace( '/(\w+)<br\s*\/*>/', '$1</li><li>', $content ) . '</li></ul>'; } else { // 如果是沒有斷行,則當作段落元素來處理。 $content = '<p>' . $content . '</p>'; }
原本的規則運算式中,使用了 \w
用來比對字串,但 \w
能比對的,只有半形英數,無法用來比對像是中文漢字或日文假名的多位元組字元 (multibyte characters)。如果要改為能夠比對多位元組字元的話,那需要用 \p{L}
這個特殊的字元類別來表示。
此外,如果回頭參考同事使用的字串內容,會發現他的字串中還有其他比對模式需要處理,例如「全形字與半形字中間應有一個半形空格」、「標點符號 %」等,因此需要將規則運算式改寫為下列形式:
if ( preg_match( '/([\w\p{L}\s%!]+)<br\s*\/*>/', $content ) ) { // 將換行標籤 <br /> 與 <br> 取代為 </li><li>,作為項目符號。 $content = '<ul><li>' . preg_replace( '/([\w\p{L}\s%!]+)<br\s*\/*>/', '$1</li><li>', $content ) . '</li></ul>'; } else { // 如果是沒有斷行,則當作段落元素來處理。 $content = '<p>' . $content . '</p>'; }
關於規則運算式的一般做法,Harris 先生與 Google Analytics 的說明文章都有基本的介紹。這邊要再補充說明字元類別:
名稱 | 說明 |
---|---|
\s | 泛空白字元 (除了半形空格外,也包含 tab、換行等) |
\d | 任何 10 進位數字,相當於 [0-9] |
\S | 非泛空白字元 |
\D | 非 10 進位數字字元 |
[字元組合] | 比對存在於 [] 間的字元組合,如 [A-Za-z0-9] 相當於 \w |
[^字元組合] | 比對非存在於 [] 間的字元組合 |
\w | 比對任何單位元文字字元 |
\W | 比對任何非文字字元 |
其他字元類別的介紹,可以參考 Microsoft 的開發文件。
這次的問題主要是一開始設計不良導致,在測試的過程中,我只用了隨機的英文字串 (如截圖的 abc、def 等),並沒有考慮到實際上寫文章的情形。