php如何用正規表達式(Regular Expression)處理unicode
最近使用正規表達式(Regular Expression)處理夾雜中英文、及符號的字串。因為字串是UTF8的編碼,於是翻了一下正規表達式的經典書籍-精通正規表達式(第三版)(這本書寫的真不錯,看了前兩章就可以感受到作者的用心與功力),看看PHP該如何處理。
書中提到PHP的表示方式為\xnum、\x{num},這和常見的\unum方式不同。照書中所述的處理方式去做,結果和預期不同。
最後看了以下兩篇PHP官網上的說明,才瞭解正確的用法
最後,在PHP中如何用正規表達式(Regular Expression)把NBSP換掉呢?請見下面範例,為了好表示被處理後的字串組成,採用urlencode()輸出。
PS:第三個範例,才是正確作法。例外兩個範例,僅為了說明PCRE UTF-8 mod、及unicode表示方式,供參考之用
關於NBSP有個小補充。使用html_entity_decode()時需注意,。html_entity_decode(' ')傳回的是NBSP,非一般的空白。以下,則是節錄PHP官方網站的說明
參考資料
書中提到PHP的表示方式為\xnum、\x{num},這和常見的\unum方式不同。照書中所述的處理方式去做,結果和預期不同。
最後看了以下兩篇PHP官網上的說明,才瞭解正確的用法
- Pattern Modifiersu,提到PCRE UTF-8 mode…
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.
- Escape sequences,這篇說明了 \xYY 和 \x{YYYY}的差異…
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不換行空格作範例說明。這兩者他們的編碼如下…
- 你,U+4F60,\xE4\xBD\xA0。 - 詳情請見你,(U+4F60)
- NBSP,U+00A0,\xC2\xA0。 - 詳情請見Unicode Character 'NO-BREAK SPACE' (U+00A0)
最後,在PHP中如何用正規表達式(Regular Expression)把NBSP換掉呢?請見下面範例,為了好表示被處理後的字串組成,採用urlencode()輸出。
PS:第三個範例,才是正確作法。例外兩個範例,僅為了說明PCRE UTF-8 mod、及unicode表示方式,供參考之用
- <?php
- //產生一個字串,由『你』及,一個NO-BREAK SPACE(U+00A0)即所謂的 組成
- $str = "\xE4\xBD\xA0\xC2\xA0";
- echo "原始字串:{$str}", PHP_EOL;
- echo urlencode($str), PHP_EOL;
- //結果
- //原始字串:你
- //%E4%BD%A0%C2%A0
- echo 'demo 1:', PHP_EOL;
- $pattern = '/\x{00A0}/';
- echo urlencode($str), PHP_EOL;
- $aft = preg_replace($pattern, ' ', $str);
- echo urlencode($aft), PHP_EOL;
- //結果
- //demo 1:
- //%E4%BD%A0%C2%A0
- //%E4%BD%26nbsp%3B%C2%26nbsp%3B
- echo 'demo 2:', PHP_EOL;
- $pattern = '/\x00A0/u'; //使用 '/\x00A0/u',會無法取代。應該是因為解釋為00。 使用'/\xA0/u'會正常。
- echo urlencode($str), PHP_EOL;
- $aft = preg_replace($pattern, ' ', $str);
- echo urlencode($aft), PHP_EOL;
- //結果
- //demo 2:
- //%E4%BD%A0%C2%A0
- //%E4%BD%A0%C2%A0
- //正確用法
- echo 'demo 3:', PHP_EOL;
- $pattern = '/\x{00A0}/u';
- echo urlencode($str), PHP_EOL;
- $aft = preg_replace($pattern, ' ', $str);
- echo urlencode($aft), PHP_EOL;
- echo PHP_EOL;
- //結果
- //demo 3:
- //%E4%BD%A0%C2%A0
- //%E4%BD%A0%26nbsp%3B
Note:註:不斷字空白為U+00A0、ASCII code 160 。一般空白為U+0020、ASCII code 32
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.
留言