2014-12-18 3 views
3

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

Быстрая коричневая лиса перепрыгнула через ленивую собаку

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

Быстрый коричневая ... ленивая собака

ближайшая реализацией я пришел была:

function truncate($string, $length, $append = NULL) { 

    if(strlen($string) <= $length) return $string; 

    $append = (strlen($append) ? sprintf(' %s ', $append) : ' ... '); 

    $start = round($length/2); 
    $start = strlen(substr($string, 0, (strpos(substr($string, $start), ' ') + $start))); 

    $end = ($start - strlen($append)); 
    $end = strlen(substr($string, 0, strrpos(substr($string, $start + strlen($append) - 1), ' '))); 

    return substr($string, 0, $start) . $append . substr($string, (strlen($string) - $end)); 
} 

Но не только это не работает гладко с строками разной длины, но также не усекает размер, как определено.

Для некоторых строк я получаю дублируюсь пустые символы (из-за неправильную математику о пустых пространствах, используемых Sprintf() более $ Append), иногда одна буквы удаляется от слова ближайшего к интерполируемой строке, а иногда слово становится разбитым пополам, когда это не должно.

выше строка, например, если он используется как:

truncate($str, 20); 

Результаты в:

шустрая ... PED через ленивую собаку

+0

Куда подходит длина 20? Вывод строки строки на самом деле равен 32, поэтому в 20 это будет «Быстрая ... ленивая собака»? –

ответ

2

Чтобы избежать усечение среднего слова, я смотрю сначала на wordwrap(), поскольку он уже имеет эту способность по умолчанию.

Таким образом, подход, который я хотел бы использовать вместо этого, - использовать wordwrap(), чтобы разделить строку на сегменты примерно на половину всей требуемой длины, минус длину строки разделителя.

Затем объедините первую строку от wordwrap(), разделителя и последней строки. (Используйте explode() для разделения вывода wordwrap() на линии).

// 3 params: input $string, $total_length desired, $separator to use 
function truncate($string, $total_length, $separator) { 
    // The wordwrap length is half the total minus the separator's length 
    // trim() is used to prevent surrounding space on $separator affecting the length 
    $len = ($total_length - strlen(trim($separator)))/2; 

    // Separate the output from wordwrap() into an array of lines 
    $segments = explode("\n", wordwrap($string, $len)); 

    // Return the first, separator, last 
    return reset($segments) . $separator . end($segments); 
} 

Попробуйте: http://codepad.viper-7.com/ai6mAK

$s1 = "The quick brown fox jumped over the lazy dog"; 
$s2 = "Lorem ipsum dolor sit amet, nam id laudem aliquid. Option utroque interpretaris eu sea, pro ea illud alterum, sed consulatu conclusionemque ei. In alii diceret est. Alia oratio ei duo."; 
$s3 = "This is some other long string that ought to get truncated and leave some stuff on the end of it."; 

// Fox... 
echo truncate($s1, 30, "..."); 
// Lorem ipsum... 
echo truncate($s2, 30, "..."); 
// Other one 
echo truncate($s3, 40, "..."); 

Выходы:

The quick...the lazy dog 
Lorem ipsum...ei duo. 
This is some...on the end of it. 

Обратите внимание на этом выводе, что последний бит ei duo немного короче. Это связано с тем, что конечная строка wordwrap() не была общей длины. Это может быть сработано, если это важно для вас, путем проверки strlen() последнего элемента из массива $segments и, если он меньше некоторого порогового значения (скажем $len/2), разбил элемент массива перед ним на слова с помощью explode() и добавит другое слово из этого массива.

Вот улучшенная версия, которая решает эту проблему, возвращаясь к второй строке от wordwrap() и выскакивая слова до тех пор, пока окончание не будет как минимум на половину длины $total_length. Это немного сложнее, но имеет более удовлетворительный результат. http://codepad.viper-7.com/mDmlL0

function truncate($string, $total_length, $separator) { 
    // The wordwrap length is half the total, minus the separator's length 
    $len = (int)($total_length - strlen($separator))/2; 

    // Separate the output from wordwrap() into an array of lines 
    $segments = explode("\n", wordwrap($string, $len)); 

    // Last element's length is less than half $len, append words from the second-last element 
    $end = end($segments); 

    // Add words from the second-last line until the end is at least 
    // half as long as $total_length 
    if (strlen($end) <= $total_length/2 && count($segments) > 2) { 
    $prev = explode(' ', prev($segments)); 
    while (strlen($end) <= $total_length/2) { 
     $end = array_pop($prev) . ' ' . $end; 
    } 
    } 

    // Return the first, separator, last 
    return reset($segments) . $separator . $end; 
} 

// Produces: 
The quick...over the lazy dog 
Lorem ipsum...Alia oratio ei duo. 
This is some other...stuff on the end of it. 
+0

Человек ... Пока я ждал ответа, я снова попытался, и я был так близко к вашему подходу. Мне не хватало только правильной логики для ** $ len **. Лично, прямо сейчас, мне не нужна строка, чтобы иметь как можно более длинную длину, если вы не возражаете, я бы хотел увидеть более расширенный подход к этому. Кроме того, я заметил, что результат получается короче, если ** $ separator ** имеет граничные пространства. –

+0

@BrunoAugusto Вы имеете в виду, что хотите, чтобы последний абзац сфокусировался лучше, чтобы приблизиться к намеченной длине? Чтобы исправить проблему с пробелами вокруг разделителя, используйте 'strlen (trim ($ separator))' вместо 'strlen ($ separator)' –

+0

Вот что я искал. Просто из любопытства, и я надеюсь, что я не злоупотребляю вами, но возможно ли иметь минимальное количество слов на каждой конечной конечной строке, независимо от определенной длины, для случаев, когда разделитель имеет больше символов, чем подстроки добавлены вокруг него? –

Смежные вопросы