По-видимому, в 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', ' Å')); }