php如何用正規表達式(Regular Expression)處理unicode

最近使用正規表達式(Regular Expression)處理夾雜中英文、及符號的字串。因為字串是UTF8的編碼,於是翻了一下正規表達式的經典書籍-精通正規表達式(第三版)(這本書寫的真不錯,看了前兩章就可以感受到作者的用心與功力),看看PHP該如何處理。

書中提到PHP的表示方式為\xnum、\x{num},這和常見的\unum方式不同。照書中所述的處理方式去做,結果和預期不同。

最後看了以下兩篇PHP官網上的說明,才瞭解正確的用法
This modifier turns on additional functionality of PCRE that is incompatible with Perl. Pattern strings are treated as UTF-8. This modifier is available from PHP 4.1.0 or greater on Unix and from PHP 4.2.3 on win32. UTF-8 validity of the pattern is checked since PHP 4.3.5.
After "\x", up to two hexadecimal digits are read (letters can be in upper or lower case). In UTF-8 mode, "\x{...}" is allowed, where the contents of the braces is a string of hexadecimal digits. It is interpreted as a UTF-8 character whose code number is the given hexadecimal number. The original hexadecimal escape sequence, \xhh, matches a two-byte UTF-8 character if the value is greater than 127.
最後,以一個中文字『你』,及NBSP不換行空格作範例說明。這兩者他們的編碼如下…
依據Escape sequences所述,\xC2\xA0是『NO-BREAK SPACE』的HEX編碼。而\x{00A0}則是U+00A0。以我的案例,是需要採用後者的表現方式。

最後,在PHP中如何用正規表達式(Regular Expression)把NBSP換掉呢?請見下面範例,為了好表示被處理後的字串組成,採用urlencode()輸出。
PS:第三個範例,才是正確作法。例外兩個範例,僅為了說明PCRE UTF-8 mod、及unicode表示方式,供參考之用
  1. <?php  
  2. //產生一個字串,由『你』及,一個NO-BREAK SPACE(U+00A0)即所謂的&nbsp;組成  
  3. $str = "\xE4\xBD\xA0\xC2\xA0";  
  4. echo "原始字串:{$str}", PHP_EOL;  
  5. echo urlencode($str), PHP_EOL;  
  6. //結果  
  7. //原始字串:你   
  8. //%E4%BD%A0%C2%A0  
  9.   
  10. echo 'demo 1:', PHP_EOL;  
  11. $pattern = '/\x{00A0}/';  
  12. echo urlencode($str), PHP_EOL;  
  13. $aft = preg_replace($pattern'&nbsp;'$str);  
  14. echo urlencode($aft), PHP_EOL;  
  15. //結果  
  16. //demo 1:  
  17. //%E4%BD%A0%C2%A0  
  18. //%E4%BD%26nbsp%3B%C2%26nbsp%3B  
  19.   
  20. echo 'demo 2:', PHP_EOL;  
  21. $pattern = '/\x00A0/u'//使用 '/\x00A0/u',會無法取代。應該是因為解釋為00。  使用'/\xA0/u'會正常。  
  22. echo urlencode($str), PHP_EOL;  
  23. $aft = preg_replace($pattern'&nbsp;'$str);  
  24. echo urlencode($aft), PHP_EOL;  
  25. //結果  
  26. //demo 2:  
  27. //%E4%BD%A0%C2%A0  
  28. //%E4%BD%A0%C2%A0  
  29.   
  30. //正確用法  
  31. echo 'demo 3:', PHP_EOL;  
  32. $pattern = '/\x{00A0}/u';  
  33. echo urlencode($str), PHP_EOL;  
  34. $aft = preg_replace($pattern'&nbsp;'$str);  
  35. echo urlencode($aft), PHP_EOL;  
  36. echo PHP_EOL;  
  37. //結果  
  38. //demo 3:  
  39. //%E4%BD%A0%C2%A0  
  40. //%E4%BD%A0%26nbsp%3B  
關於NBSP有個小補充。使用html_entity_decode()時需注意,。html_entity_decode(' ')傳回的是NBSP,非一般的空白。以下,則是節錄PHP官方網站的說明
Note:
You might wonder why trim(html_entity_decode(' ')); doesn't reduce the string to an empty string, that's because the ' ' entity is not ASCII code 32 (which is stripped by trim()) but ASCII code 160 (0xa0) in the default ISO 8859-1 encoding.
註:不斷字空白為U+00A0、ASCII code 160 。一般空白為U+0020、ASCII code 32


參考資料
html_entity_decode()
你,(U+4F60)
Unicode Character 'NO-BREAK SPACE' (U+00A0)
何謂NBSP不換行空格
精通正規表達式(第三版)

留言