2010-04-21 5 views
7

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

function Text_Truncate($string, $limit, $more = '...') 
{ 
    $string = trim(html_entity_decode($string, ENT_QUOTES, 'UTF-8')); 

    if (strlen(utf8_decode($string)) > $limit) 
    { 
     $string = preg_replace('~^(.{1,' . intval($limit) . '})(?:\s.*|$)~su', '$1', $string); 

     if (strlen(utf8_decode($string)) > $limit) 
     { 
      $string = preg_replace('~^(.{' . intval($limit) . '}).*~su', '$1', $string); 
     } 

     $string .= $more; 
    } 

    return trim(htmlentities($string, ENT_QUOTES, 'UTF-8', true)); 
} 

Здесь некоторые тесты:

// Iñtërnâtiônàlizætiøn and then the quick brown fox... (49 + 3 chars) 
echo dyd_Text_Truncate('Iñtërnâtiônàlizætiøn and then the quick brown fox jumped overly the lazy dog and one day the lazy dog humped the poor fox down until she died.', 50, '...'); 

// Iñtërnâtiônàlizætiøn_and_then_the_quick_brown_fox_... (50 + 3 chars) 
echo dyd_Text_Truncate('Iñtërnâtiônàlizætiøn_and_then_the_quick_brown_fox_jumped_overly_the_lazy_dog and one day the lazy dog humped the poor fox down until she died.', 50, '...'); 

Они оба работают, как это, однако, если я бросаю второй preg_replace() я получаю следующее:

Iñtërnâtiônàlizætiøn_and_then_the_quick_brown_fox_jumped_overly_the_lazy_dog и один день лентяй горбатые в бедную лису вниз, пока она не умерла ....

Я не могу использовать substr() потому что он работает только на уровне байтов и не имеют доступа к mb_substr() ATM, я сделал несколько попыток присоединиться к второму регулярному выражению с первым, но безуспешно.

Пожалуйста, помогите S.M.S., я боролся с этим почти час.


EDIT: Я сожалею, я не спал в течение 40 часов, и я бессовестно пропустил это:

$string = preg_replace('~^(.{1,' . intval($limit) . '})(?:\s.*|$)?~su', '$1', $string); 

Тем не менее, если кто-то имеет более оптимизированный регулярное выражение (или тот, который игнорирует тянущаяся пространство), пожалуйста, поделитесь:

"Iñtërnâtiônàlizætiøn and then " 
"Iñtërnâtiônàlizætiøn_and_then_" 

EDIT 2: Я до сих пор не могу избавиться от задних пробелов, может кто-нибудь помочь мне?

РЕДАКТИРОВАТЬ 3: Хорошо, ни одно из моих исправлений действительно не работает, меня обманывает RegexBuddy - я должен, вероятно, оставить это на другой день и немного поспать. На сегодня.

+3

Бедные лисы. _____ – kennytm

+0

Почему вы не используете 'trim', чтобы избавиться от конечного пробела? – Jens

+3

Пробудитесь в течение 40 часов и занимайтесь регулярным выражением. +1 жалость. –

ответ

3

Может быть, я могу дать вам счастливое утро после долгой ночи RegExp кошмаров:

'~^(.{1,' . intval($limit) . '}(?<=\S)(?=\s)|.{'.intval($limit).'}).*~su' 

Кипение его вниз:

^  # Start of String 
(  # begin capture group 1 
.{1,x} # match 1 - x characters 
(?<=\S)# lookbehind, match must end with non-whitespace 
(?=\s) # lookahead, if the next char is whitespace, match 
|  # otherwise test this: 
.{x} # got to x chars anyway. 
)  # end cap group 
.*  # match the rest of the string (since you were using replace) 

Вы всегда можете добавить |$ до конца из (?=\s), но поскольку ваш код уже проверял, что длина строки была длиннее, чем $limit, я не чувствовал, что этот случай был бы необходим.

+0

Больше «счастливого дня», но спасибо gnarf! Я заснул, создав впечатление, что мне придется использовать lookahead или просто использовать 'trim()'. Еще раз спасибо! –

0

Считаете ли вы использование wordwrap? (http://us3.php.net/wordwrap)

+1

Да, это медленнее для больших строк и не работает с многобайтовыми символами. –