Многобитовая обрезка в PHP?

По-видимому, в mb_* нет mb_trim , поэтому я пытаюсь реализовать его самостоятельно.

Я недавно нашел это регулярное выражение в комментарии на php.net :

 /(^\s+)|(\s+$)/u 

Поэтому я бы выполнил его следующим образом:

 function multibyte_trim($str) { if (!function_exists("mb_trim") || !extension_loaded("mbstring")) { return preg_replace("/(^\s+)|(\s+$)/u", "", $str); } else { return mb_trim($str); } } 

Регулярное выражение кажется правильным для меня, но я чрезвычайно noob с регулярными выражениями. Удастся ли это удалить любое Unicode-пространство в начале / конце строки?

Стандартная функция отделки обрезает несколько пространственных и пространственных символов. Они определяются как символы ASCII, что означает определенные конкретные байты от 0 до 0100 0000 .

Правильный ввод UTF-8 никогда не будет содержать многобайтовые символы, состоящие из байтов 0xxx xxxx . Все байты правильных многобайтовых символов UTF-8 начинаются с 1xxx xxxx .

Это означает, что в правильной последовательности UTF-8 байты 0xxx xxxx могут ссылаться только на однобайтные символы. Поэтому функция trim PHP никогда не убирает «половину символа», если у вас есть правильная последовательность UTF-8. (Будьте очень осторожны в отношении ненадлежащих последовательностей UTF-8 .)


Регулярные выражения \s в ASCII будут в основном соответствовать тем же символам, что и trim .

Функции preg с модификатором /u работают только с регулярными выражениями , закодированными в UTF-8 , и /\s/u соответствуют также nbsp UTF8. Такое поведение с неразрывными пробелами является единственным преимуществом его использования.

Если вы хотите заменить символы пробела в других кодировках, не поддерживающих ASCII, ни один из методов не будет работать.

Другими словами, если вы пытаетесь обрезать обычные пространства ASCII-совместимой строкой, просто используйте trim . При использовании /\s/u будьте осторожны со значением nbsp для вашего текста.


Береги себя:

  $s1 = html_entity_decode(" Hello   "); // the NBSP $s2 = " 𩸽 exotic test ホ 𩸽 "; echo "\nCORRECT trim: [". trim($s1) ."], [". trim($s2) ."]"; echo "\nSAME: [". trim($s1) ."] == [". preg_replace('/^\s+|\s+$/','',$s1) ."]"; echo "\nBUT: [". trim($s1) ."] != [". preg_replace('/^\s+|\s+$/u','',$s1) ."]"; echo "\n!INCORRECT trim: [". trim($s2,'𩸽 ') ."]"; // DANGER! not UTF8 safe! echo "\nSAFE ONLY WITH preg: [". preg_replace('/^[𩸽\s]+|[𩸽\s]+$/u', '', $s2) ."]"; 

Я не знаю, что вы пытаетесь сделать с этой бесконечной рекурсивной функцией, которую вы определяете, но если вы просто хотите многобилетную защиту, это будет работать.

 function mb_trim($str) { return preg_replace("/(^\s+)|(\s+$)/us", "", $str); } 

Эта версия поддерживает второй необязательный параметр $ charlist:

 function mb_trim ($string, $charlist = null) { if (is_null($charlist)) { return trim ($string); } else { $charlist = str_replace ('/', '\/', preg_quote ($charlist)); return preg_replace ("/(^[$charlist]+)|([$charlist]+$)/us", '', $string); } } 

Однако не поддерживает «..» для диапазонов.

Вы также можете обрезать не-ascii-совместимые пространства (например, не preg_replace('/^\p{Z}+|\p{Z}+$/u','',$str); пространство) в строках UTF-8 с preg_replace('/^\p{Z}+|\p{Z}+$/u','',$str);

\s будет соответствовать только символу пробела «ascii compatible» даже с модификатором u .
но \p{Z} будет соответствовать всем известным символам пробела unicode

mb_ereg_replace, похоже, обойдет это:

 function mb_trim($str,$regex = "(^\s+)|(\s+$)/us") { return mb_ereg_replace($regex, "", $str); } 

.. но я не знаю достаточно о регулярных выражениях, чтобы знать, как вы добавили бы в параметр «charlist», который люди ожидали бы иметь возможность комбинировать с trim () – то есть список символов для обрезки – так что просто сделал параметр regex a.

Возможно, у вас может быть массив специальных символов, а затем пропустите его для каждого символа в charlist и, соответственно, избегайте их при создании строки регулярного выражения.

Хорошо, поэтому я принял решение @ edson-medina и исправил ошибку и добавил некоторые модульные тесты. Вот три функции, которые мы используем, чтобы предоставить mb-копии для обрезки, rtrim и ltrim.

 //////////////////////////////////////////////////////////////////////////////////// //Add some multibyte core functions not in PHP //////////////////////////////////////////////////////////////////////////////////// function mb_trim($string, $charlist = null) { if (is_null($charlist)) { return trim($string); } else { $charlist = preg_quote($charlist, '/'); return preg_replace("/(^[$charlist]+)|([$charlist]+$)/us", '', $string); } } function mb_rtrim($string, $charlist = null) { if (is_null($charlist)) { return rtrim($string); } else { $charlist = preg_quote($charlist, '/'); return preg_replace("/([$charlist]+$)/us", '', $string); } } function mb_ltrim($string, $charlist = null) { if (is_null($charlist)) { return ltrim($string); } else { $charlist = preg_quote($charlist, '/'); return preg_replace("/(^[$charlist]+)/us", '', $string); } } //////////////////////////////////////////////////////////////////////////////////// 

Вот блок-тесты, которые я написал для всех, кто интересуется:

 public function test_trim() { $this->assertEquals(trim(' foo '), mb_trim(' foo ')); $this->assertEquals(trim(' foo ', ' o'), mb_trim(' foo ', ' o')); $this->assertEquals('foo', mb_trim(' Åfooホ ', ' Åホ')); } public function test_rtrim() { $this->assertEquals(rtrim(' foo '), mb_rtrim(' foo ')); $this->assertEquals(rtrim(' foo ', ' o'), mb_rtrim(' foo ', ' o')); $this->assertEquals('foo', mb_rtrim('fooホ ', ' ホ')); } public function test_ltrim() { $this->assertEquals(ltrim(' foo '), mb_ltrim(' foo ')); $this->assertEquals(ltrim(' foo ', ' o'), mb_ltrim(' foo ', ' o')); $this->assertEquals('foo', mb_ltrim(' Åfoo', ' Å')); }