Объединение двух регулярных выражений для усечения слов в строках - PullRequest
7 голосов
/ 21 апреля 2010

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

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, я сделал несколько попыток присоединиться ко второму регулярному выражению с первым, но безуспешно.

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


РЕДАКТИРОВАТЬ: Извините, я не спал в течение 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_"

РЕДАКТИРОВАТЬ 2: Я все еще не могу избавиться от конечных пробелов, кто-нибудь может мне помочь?

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

Ответы [ 2 ]

3 голосов
/ 22 апреля 2010

Возможно, я могу подарить вам счастливое утро после долгой ночи кошмаров 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 голосов
/ 22 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...