我正在尝试将长字符串截断为特定数量的字符,并在其中间插入另一个用户定义的字符串(或多或少)以表示该字符串已被截断。与此同时,我正试图让这些话不要被打破。 E.g:
快速的棕色狐狸跳过懒狗
如果定义(作为函数参数)将此字符串截断为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 );
结果:
快速的棕色......趴在懒狗身上
答案 0 :(得分: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.