2012-04-08 4 views
29

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

Недавно я нашел это регулярное выражение в комментарии в 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); 
    } 
} 

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

+4

Похоже бесконечной рекурсии ко мне ... – knittl

+1

облицовку() будут удалены символы, такие как ", \ т, \ г \ п, \ 0, \ x0B "и \ s модификатор как", \ t, \ r, \ n, \ v, \ f ", так что это не так, как вы хотите, я думаю. Чтобы удалить некоторые специальные символы из строки, вы всегда можете использовать trim ($ str, $ charlist) со вторым параметром. Можете ли вы написать несколько примеров символов, которые хотите удалить? – Naki

+0

Какие символы вы хотите удалить, что trim() не удаляется? – Niko

ответ

37

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

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

Это означает, что в правильной последовательности UTF-8 байты 0xxx xxxx могут ссылаться только на однобайтные символы. Таким образом, функция PHP trim никогда не убирает «половину символа» при условии, что у вас есть UTF-8. (Будьте очень careful about improper UTF-8 sequences.)


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

preg В функции с модификатором /u работает только на UTF8 кодированных регулярных выражений и /\s/u матча также UTF8-х nbsp. Такое поведение с неразрывными пробелами является единственным преимуществом его использования.

Если вы хотите заменить символы пробела другими, не кодирующими 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) ."]"; 
+0

Я думаю, что буду придерживаться 'trim', спасибо – federicot

+0

' trim ($ s, '') 'и' trim ($ s, '') 'отлично работает (!). Второй пример содержит символ ASCII, который работает вместе ... Таким образом, мы можем сказать: '' 'trim()' функция является безопасным UTF8 *, но не '' trim() 'является ASCII, равно UTF8. Люди путаются о '/ \ s /' и '/ \ s/u', где только последний обнаруживает NBSP. –

+1

неправильный! это может показаться работающим 'trim ($ s, '')', но оно может разбить строку на недопустимую последовательность UTF-8. не используйте его! – Wes

14

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

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

Являются ли pregs в PHP осведомленными о различных кодировках? Я не помню, но я знаю, что с ними когда-то была проблема, и я думаю, что это было здесь. – Incognito

+4

@Incognito Модификатор/u делает preg unicode осведомленным –

+0

'trim ($ s, '')' и 'trim ($ s, '')' отлично работает (!). Почему нам нужно 'mb_trim()'? –

2

mb_ereg_replace кажется обойти это:

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

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

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

3

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

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

+0

Я редактировал @deceze, см. О '/ \ s/u', неправильно сказать, что« будет соответствовать только ASCII »(потому что   не ASCII), можете ли вы исправить его в своем ответе? О '\ p {Z}', извините, я не привел в моем редактировании там, хорошо помнить его (!). –

5

Эта версия поддерживает второй необязательный параметр $ 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); 
    } 
} 

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

+1

Мне нравится ваш путь, но не забудьте предварительно просмотреть свой $ charlist :) –

+0

Nice catch! Спасибо. –

+1

Это не работает для 'mb_trim ('000foo000', '0')' ...: -3 – deceze

3

Хорошо, поэтому я принял решение @ 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', ' Å')); 
} 
Смежные вопросы