PHP 日本大会 2024

wordwrap

(PHP 4 >= 4.0.2, PHP 5, PHP 7, PHP 8)

wordwrap将字符串换行到指定字符数

描述

wordwrap(
    字符串 $string,
    整数 $width = 75,
    字符串 $break = "\n",
    布尔值 $cut_long_words = false
): 字符串

使用字符串换行符将字符串换行到指定的字符数。除非cut_long_words设置为true,否则字符串会在空格 (U+0020) 字符后换行。

参数

string

输入字符串。

width

字符串将被换行的字符数。

break

使用可选的break参数换行。它不能是空字符串。

cut_long_words

如果cut_long_words设置为true,则字符串始终在指定width处或之前换行。因此,如果有一个单词大于给定的宽度,则会将其拆分。(参见第二个示例)。当为false时,即使width小于单词宽度,函数也不会分割单词。

返回值

返回在指定长度处换行的给定字符串。

错误/异常

如果break是空字符串,则会抛出ValueError异常。

变更日志

版本 描述
8.0.0 如果break为空字符串,则会抛出ValueError异常;以前在这种情况下,它会发出E_WARNING警告并返回false

示例

示例 #1 wordwrap() 示例

<?php
$text
= "The quick brown fox jumped over the lazy dog.";
$newtext = wordwrap($text, 20, "<br />\n");

echo
$newtext;
?>

以上示例将输出

The quick brown fox<br />
jumped over the lazy<br />
dog.

示例 #2 wordwrap() 示例

<?php
$text
= "A very long woooooooooooord.";
$newtext = wordwrap($text, 8, "\n", true);

echo
"$newtext\n";
?>

以上示例将输出

A very
long
wooooooo
ooooord.

示例 #3 wordwrap() 示例

<?php
$text
= "A very long woooooooooooooooooord. and something";
$newtext = wordwrap($text, 8, "\n", false);

echo
"$newtext\n";
?>

以上示例将输出

A very
long
woooooooooooooooooord.
and
something

参见

  • nl2br() - 在字符串中所有换行符之前插入 HTML 换行符
  • chunk_split() - 将字符串拆分为较小的块

添加注释

用户贡献注释 19 条注释

ju1ius
12 年前
使用正则表达式的另一种 UTF-8 安全 wordwrap 解决方案。
性能相当好,并且以线性时间工作。

<?php
function utf8_wordwrap($string, $width=75, $break="\n", $cut=false)
{
if(
$cut) {
// 匹配任何长度为 1 到 $width 个字符的字符串,后跟空格或 EOS,
// 否则匹配任何长度为 $width 个字符的字符串
$search = '/(.{1,'.$width.'})(?:\s|$)|(.{'.$width.'})/uS';
$replace = '$1$2'.$break;
} else {
// 使用先行断言锚定模式的开头
// 避免单词长度超过 $width 时出现疯狂的回溯
$pattern = '/(?=\s)(.{1,'.$width.'})(?:\s|$)/uS';
$replace = '$1'.$break;
}
return
preg_replace($search, $replace, $string);
}
?>
当然,如果参数来自不受信任的输入,不要忘记对 $width 和 $break 参数使用 preg_quote。
michdingpayc
2 年前
对 10 年前 ju1ius 的 UTF-8 安全 wordwrap 的更正。
此版本解决了在输入字符串中的第一个和最后一个单词中未添加换行符的问题。

<?php
函数 utf8_wordwrap($string, $width=75, $break="\n", $cut=false)
{
if(
$cut) {
// 匹配任何长度为 1 到 $width 个字符的字符串,后跟空格,
// 否则匹配任何长度为 $width 个字符的字符串
$search= '/(.{1,'.$width.'})(?:\s)|(.{'.$width.'})(?!$)/uS';
$replace = '$1$2'.$break;
} else {
// 使用后视断言锚定模式的开头
// 避免当单词长度超过 $width 时出现疯狂回溯
$search= '/(?<=\s|^)(.{1,'.$width.'}\S*)(?:\s)/uS';
$replace = '$1'.$break;
}
return
preg_replace($search, $replace, $string);
}
?>
Dave Lozier - dave at fusionbb.com
19 年前
如果您想换行长文本字符串但又不想破坏 HTML,您可能会发现此函数很有用。对我来说似乎有效,希望对您也有效。享受!:)

<?php
函数 textWrap($text) {
$new_text = '';
$text_1 = explode('>',$text);
$sizeof = sizeof($text_1);
for (
$i=0; $i<$sizeof; ++$i) {
$text_2 = explode('<',$text_1[$i]);
if (!empty(
$text_2[0])) {
$new_text .= preg_replace('#([^\n\r .]{25})#i', '\\1 ', $text_2[0]);
}
if (!empty(
$text_2[1])) {
$new_text .= '<' . $text_2[1] . '>';
}
}
return
$new_text;
}
?>
Alhadis
9 年前
对于那些有兴趣将文本换行以适应*像素*宽度(而不是字符)的人来说,您可能会发现以下函数很有用;尤其是在动态生成的图像上换行文本时。

如果某个单词太长而无法容纳在可用空间中,它会根据需要进行断字以适应容器。此操作是递归进行的,因此非常长的单词或名称(例如,URL 或这个人的签名 - http://en.wikipedia.org/wiki/Wolfe+585,_Senior)仍然会在超过第四行或第五行后被截断,或者其他任何行。

<?php

/**
* 将字符串换行到指定像素宽度。
*
* 此函数的功能类似于PHP的原生wordwrap函数;但是,
* 它根据字体和字号计算换行,而不是根据字符数。这
* 对于包含大量细字符的句子,可以生成更均匀的换行。
*
* @static $mult;
* @param string $text - 输入字符串。
* @param float $width - 文本换行区域的宽度(像素)。
* @param float $size - 字体的字号(像素)。
* @param string $font - 用于测量文本的字体路径。
* @return string 在检测到的换行点手动插入换行符后的原始字符串。
*/
function pixel_word_wrap($text, $width, $size, $font){

# 传递空值?提前退出。
if(!$text) return $text;

# 检查imagettfbbox是否期望字体大小以磅或像素表示。
static $mult;
$mult = $mult ?: version_compare(GD_VERSION, '2.0', '>=') ? .75 : 1;

# 文本无需换行即可适应指定空间。
$box = imagettfbbox($size * $mult, 0, $font, $text);
if(
$box[2] - $box[0] / $mult < $width) return $text;

# 开始测量输入的每一行,并在检测到溢出时插入换行符。
$output = '';
$length = 0;

$words = preg_split('/\b(?=\S)|(?=\s)/', $text);
$word_count = count($words);
for(
$i = 0; $i < $word_count; ++$i){

# 换行符
if(PHP_EOL === $words[$i])
$length = 0;

# 去除任何前导制表符。
if(!$length) $words[$i] = preg_replace('/^\t+/', '', $words[$i]);

$box = imagettfbbox($size * $mult, 0, $font, $words[$i]);
$m = $box[2] - $box[0] / $mult;

# 这是一个很长的单词,所以尝试对其进行断字。
if(($diff = $width - $m) <= 0){
$diff = abs($diff);

# 确定从单词的哪一端开始测量。在已经非常耗时的函数中节省了一些额外的周期。
if($diff - $width <= 0) for($s = strlen($words[$i]); $s; --$s){
$box = imagettfbbox($size * $mult, 0, $font, substr($words[$i], 0, $s) . '-');
if(
$width > ($box[2] - $box[0] / $mult) + $size){
$breakpoint = $s;
break;
}
}

else{
$word_length = strlen($words[$i]);
for(
$s = 0; $s < $word_length; ++$s){
$box = imagettfbbox($size * $mult, 0, $font, substr($words[$i], 0, $s+1) . '-');
if(
$width < ($box[2] - $box[0] / $mult) + $size){
$breakpoint = $s;
break;
}
}
}

if(
$breakpoint){
$w_l = substr($words[$i], 0, $s+1) . '-';
$w_r = substr($words[$i], $s+1);

$words[$i] = $w_l;
array_splice($words, $i+1, 0, $w_r);
++
$word_count;
$box = imagettfbbox($size * $mult, 0, $font, $w_l);
$m = $box[2] - $box[0] / $mult;
}
}

# 如果当前行没有足够的空间容纳下一个单词,则开始新的一行。
if($length > 0 && $length + $m >= $width){
$output .= PHP_EOL;
$length = 0;

# 如果当前单词只是一个空格,则不必理会。跳过(避免文本中出现奇怪的间隙)。
if(' ' === $words[$i]) continue;
}

# 写入另一个单词并增加当前行的总长度。
$output .= $words[$i];
$length += $m;
}

return
$output;
};

?>
frans-jan at van-steenbeek dot R-E-M-O-V-E dot net
19 年前
使用wordwrap函数对于格式化电子邮件消息很有用,但它有一个缺点:换行符通常被视为空格,导致奇怪的行为,包括只在一个单词后换行的行。

为了解决这个问题,我使用了这个

<?php
function linewrap($string, $width, $break, $cut) {
$array = explode("\n", $string);
$string = "";
foreach(
$array as $key => $val) {
$string .= wordwrap($val, $width, $break, $cut);
$string .= "\n";
}
return
$string;
}
?>

然后我使用linewrap()代替wordwrap()

希望这对某些人有所帮助
altin_bardhi at yahoo dot co dot uk
13年前
这里我提供了一个可能非常有用的文本自动换行代码片段。

这段代码的功能是:它接收输入文本,查找长度超过定义的‘$chunk_length’的单词;如果找到,则将长单词分割,然后将整个字符串连接回一个新字符串,其中较长的单词用破折号字符(此处为“-”)分隔。

完成此任务后,它会在指定的‘$line_length’后插入HTML换行符(取决于您的容器宽度要求)。

<?php

//开始函数 explode_wrap
function explode_wrap($text, $chunk_length, $line_length){

//将字符串中空格分隔的所有单词分割
$string_chunks = explode(' ', $text);

// 获取数组 $sring_chunks_array 中每个分割的单词 => 键 => 值
foreach ($string_chunks as $chunk => $value) {

if(
strlen($value) >= $chunk_length){

//分割长度超过 $chunk_length 的块/单词
$new_string_chunks[$chunk] = chunk_split($value, $chunk_length, ' - ');

}else {

//不要分割正常长度的单词
$new_string_chunks[$chunk] = $value;

}

}
//结束 foreach 循环

//将所有单词连接回去
$new_text=implode(' ', $new_string_chunks);

return
wordwrap($new_text, $line_length, '<br />');

}
//结束函数

?>
Peter
17年前
当单元格中包含文本时,主要问题是过长的单词会拉伸单元格边距。此函数将把文本中超过 $nr 个字符的单词用“-”字符断开。

<?php
function processtext($text,$nr=10)
{
$mytext=explode(" ",trim($text));
$newtext=array();
foreach(
$mytext as $k=>$txt)
{
if (
strlen($txt)>$nr)
{
$txt=wordwrap($txt, $nr, "-", 1);
}
$newtext[]=$txt;
}
return
implode(" ",$newtext);
}
?>
php at maranelda dot org
16年前
任何尝试编写文本电子邮件客户端的人都应该注意以下事项

<?php

$a
= "some text that must wrap nice";

$a = wordwrap($a, 9);

echo
$a;

// some text
// that must
// wrap nice

$a = wordwrap($a, 9);

echo
$a;

// some text
// that
// must
// wrap
// nice

?>

对已经换行的文本重复使用wordwrap()函数时,会将行尾字符考虑在内计算行长,因此第一次刚好合适排列的每一行在第二次处理时都会被认为长了一个字符。在准备包含(例如)已进行过自动换行的转发邮件的文本电子邮件时,这可能是个问题。

下面的解决方案使用explode()函数根据行尾符分割文本,并分别对生成的字符串使用wordwrap()函数进行处理,可以很好地解决这个问题。
info at hsdn dot org
13年前
支持UTF-8的自动换行,返回数组。

<?php

function mb_wordwrap_array($string, $width)
{
if ((
$len = mb_strlen($string, 'UTF-8')) <= $width)
{
return array(
$string);
}

$return = array();
$last_space = FALSE;
$i = 0;

do
{
if (
mb_substr($string, $i, 1, 'UTF-8') == ' ')
{
$last_space = $i;
}

if (
$i > $width)
{
$last_space = ($last_space == 0) ? $width : $last_space;

$return[] = trim(mb_substr($string, 0, $last_space, 'UTF-8'));
$string = mb_substr($string, $last_space, $len, 'UTF-8');
$len = mb_strlen($string, 'UTF-8');
$i = 0;
}

$i++;
}
while (
$i < $len);

$return[] = trim($string);

return
$return;
}

?>
$del=' at '; 'sanneschaap' dot $del dot 'gmail dot com'
16年前
这些函数允许您根据比例字体(此处为 Arial,11px)的实际显示宽度来换行字符串。在某些情况下非常方便,因为CSS3尚未完全支持。100个字符串约需5毫秒。

我的旧绵羊换行函数(发布在本页底部,有点过时了),这个函数更快且更准确。

<?php
//最大字符宽度 @
$fontwidth = 11;

//每个字符组包含显示宽度相同的字符的序数值
$chargroup[0] = array(64);
$chargroup[1] = array(37,87,119);
$chargroup[2] = array(65,71,77,79,81,86,89,109);
$chargroup[3] = array(38,66,67,68,72,75,78,82,83,85,88,90);
$chargroup[4] = array(35,36,43,48,49,50,51,52,53,54,55,56,57,60,61,62,63, 69,70,76,80,84,95,97,98,99,100,101,103,104,110,111,112, 113,115,117,118,120,121,122,126);
$chargroup[5] = array(74,94,107);
$chargroup[6] = array(34,40,41,42,45,96,102,114,123,125);
$chargroup[7] = array(44,46,47,58,59,91,92,93,116);
$chargroup[8] = array(33,39,73,105,106,108,124);

//显示宽度与最大字符宽度的比例
$chargroup_relwidth[0] = 1; //字符 @
$chargroup_relwidth[1] = 0.909413854;
$chargroup_relwidth[2] = 0.728241563;
$chargroup_relwidth[3] = 0.637655417;
$chargroup_relwidth[4] = 0.547069272;
$chargroup_relwidth[5] = 0.456483126;
$chargroup_relwidth[6] = 0.36589698;
$chargroup_relwidth[7] = 0.275310835;
$chargroup_relwidth[8] = 0.184724689;

//构建快速数组
$char_relwidth = null;
for (
$i=0;$i<count($chargroup);$i++){
for (
$j=0;$j<count($chargroup[$i]);$j++){
$char_relwidth[$chargroup[$i][$j]] = $chargroup_relwidth[$i];
}
}

//获取字符串的显示宽度(以像素为单位)
function get_str_width($str){
global
$fontwidth,$char_relwidth;
$result = 0;
for (
$i=0;$i<strlen($str);$i++){
$result += $char_relwidth[ord($str[$i])];
}
$result = $result * $fontwidth;
return
$result;
}

//在特定显示像素宽度处截断字符串
function truncate_str_at_width($str, $width, $trunstr='...'){
global
$fontwidth,$char_relwidth;
$trunstr_width = get_str_width($trunstr);
$width -= $trunstr_width;
$width = $width/$fontwidth;
$w = 0;
for (
$i=0;$i<strlen($str);$i++){
$w += $char_relwidth[ord($str[$i])];
if (
$w > $width)
break;
}
$result = substr($str,0,$i).$trunstr;
return
$result;
// texas 是导致早上10点规则的原因 :)
}
?>
clearcrescendo.com上的答案
5年前
wordwrap() 函数使用换行符作为检测到的换行符和插入的换行符,因此在使用 wordwrap() 之前,必须将文本标准化为所需的换行符,否则,无论文本中现有换行符的位置如何,都会插入换行符。

<?php
$linebreak
= '<br/>' . PHP_EOL;
$width = 5;
$standardized = preg_replace('/\r?\n/',$linebreak, "abc abc abc\nabc abc abc\r\nabc abc abc");
echo
'标准化的EOL:', PHP_EOL, $standardized, PHP_EOL, PHP_EOL; // PHP_EOL 用于命令行,'<br/>' 用于HTML。
echo "以 $width 为宽度换行:", PHP_EOL, wordwrap( $standardized, 7, $linebreak), PHP_EOL;
?>

$ php -f test.php
标准化的EOL
abc abc abc<br/>
abc abc abc<br/>
abc abc abc

每行5个字符换行
abc abc<br/>
abc<br/>
abc abc<br/>
abc<br/>
abc abc<br/>
abc
kozimbek at mail dot ru
9 年前
在搜索并厌倦了许多地方许多无效的mb_wordwrap函数后,我终于创建了一个非常简单且有效的解决方案。

<?php
function mb_wordwrap($string, $limit)
{
$string = strip_tags($string); //去除文本中的HTML标签
$string = html_entity_decode($string); //将HTML特殊字符转换为普通文本
$string = str_replace(array("\r", "\n"), "", $string); //也去除换行符
if(mb_strlen($string, "UTF-8") <= $limit) return $string; //如果输入字符串的长度不超过截断长度,则返回未经处理的字符串
$last_space = mb_strrpos(mb_substr($string, 0, $limit, "UTF-8"), " ", 0, "UTF-8"); //查找最后一个空格符号的位置

return mb_substr($string, 0, $last_space, "UTF-8").' ...'; //返回截断到最后一个空格的字符串长度,并添加省略号
}
?>

该函数只是搜索范围内最后一个空格符号,并返回截断到该位置的字符串。无需迭代,无需正则表达式,也无需缓冲区超载。已使用大型俄语文本进行测试,运行完美。
Marcin Dobruk [zuku3000 at yahoo dot co dot uk]
15年前
从左到右(标准)和从右到左的自动换行。

<?php
function myWordWrap ($string, $length=3, $wrap=',', $from='left') {
if (
$from=='left') $txt=wordwrap($string, $length, $wrap, true);
if (
$from=='right') {
// 字符串转数组
$arr_l=array();
for (
$a=0;strlen($string)>$a;$a++) $arr_l[$a]=$string{$a};
// 反转数组
$arr_r=array_reverse($arr_l);
// 数组转字符串
$string_r='';
foreach (
$arr_r as $arr_line => $arr) $string_r.=$arr;
// 向反转字符串添加换行符
$string_r=wordwrap($string_r, $length, $wrap, true);
// 反转字符串为数组
$arr_r=array();
for (
$a=0;strlen($string_r)>$a;$a++) $arr_r[]=$string_r{$a};
// 再次反转数组
$arr_l=array_reverse($arr_r);
// 带换行符的字符串
$txt='';
foreach (
$arr_l as $arr_line => $arr) $txt.=$arr;
}
return
$txt;
}
?>
ojs-hp at web dot de
15年前
在我将BB文本转换为HTML的函数出现一些问题后。长单词无法真正适应布局,而仅仅使用wordwarp()还会在适合布局或破坏其他HTML标签的单词中添加换行符……
所以这是我的解决方案。只有字符串长度(strlen()) >= 40的单词才会用wordwarp()进行编辑。

<?php
function bb2html($bb) {
$words= explode(' ', $bb); // 字符串转数组
foreach ($words as $word) {
$break = 0;
for (
$i = 0; $i < strlen($word); $i++) {
if (
$break >= 40) {
$word= wordwrap($word, 40, '-<br>', true); //每40个字符添加<br>
$break = 0;
}
$break++;

}
$newText[] = $word; //将单词添加到数组
}
$bb = implode(' ', $newText); //数组转字符串
return $bb;
}
?>
maikuolan at gmail dot com
11年前
(回复: kouber at php dot net)。

测试您的函数,我可以确认它有效,而且运行良好。

但是,打算使用您的函数的其他用户需要注意,如果他们将其与未经验证的数据(例如来自$_POST、$_GET等的原始用户输入)一起使用,他们就会创建潜在的攻击媒介,黑客可以通过包含恶意代码的脚本请求来利用这些媒介。这是因为您的函数将preg_replace函数与“e”标志一起使用(为了允许chunk_split位执行),这允许执行任意代码。

解决方案:如果存在任何可能导致$str包含未经验证的数据(例如原始用户输入),请确保在将其发送到wrap($str,…)之前对$str的内容进行清理(例如使用htmlentities/htmlspecialchars/等)。

这不是批评;我打算使用您的函数,因为我喜欢它。但是,只是将其发布为对可能不知道数据清理重要性的其他用户的说明。
phil_marmotte at yahoo dot fr
10年前
另一个从左或右的自动换行

public static function myWordWrap ($string, $length=3, $wrap=',', $from='left') {
if ($from=='left') $txt=wordwrap($string, $length, $wrap, true);
if ($from=='right') {
$m = strlen($string)%$length;
if ($m < strlen($string))
$txt = substr($string,0,$m).$wrap.wordwrap(substr($string,$m),$length, $wrap, true);
else
$txt = $string;
}

return $txt;
}
tuxedobob
7年前
应该注意的是,$break参数的行为解释得很差。

如果指定$break参数,则*该字符串定义函数认为的“换行符”*。

考虑以下字符串

$str = "Rumplestiltskin Schwartzmenikoff
1534 Gingerbread Lane
Black Forest, Germany";

您试图将此地址放入仅允许22个字符的空间中,但您希望清楚地表明您正在继续上一行,因此您希望添加空格。您可以尝试这样:

$str = wordwrap($str, 22, "\n>");

如果这样做,您将得到以下输出:

"Rumplestiltskin
>Schwartzmenikoff
1534
>Gingerbread Lane
Black
>Forest, Germany"

这是因为当您传递 "\n>" 作为第三个参数时,它假定整个字符串是一个换行符。它不再使用 "\n"。当然,在您的输出中,\n 仍然是一个换行符,因此它看起来有多余的行。

如果您想使用除换行符以外的其他字符对多行字符串进行换行,请确保所有现有的换行符都已使用您传递给wordwrap()的字符串进行分隔。
joachim
16年前
在php 5.1和5.2中,wordwrap计算字符的方式似乎有所不同(全部在Mac OSX 10.5.2上)。

/Applications/MAMP/bin/php5/bin/php --version
PHP 5.1.6 (cli) (built: Sep 8 2006 10:25:04)

/Applications/MAMP/bin/php5/bin/php -r 'echo wordwrap("In aller Freundschaft (50)_UT", 20) . "\n";'
In aller
Freundschaft
(50)_UT

php --version
PHP 5.2.5 (cli) (built: Feb 20 2008 12:30:47)

php -r 'echo wordwrap("In aller Freundschaft (50)_UT", 20) . "\n";'
In aller
Freundschaft (50)_UT
zac dot hester at gmail dot com
9 年前
我最近遇到了另一个贡献者(frans-jan at van-steenbeek dot R-E-M-O-V-E dot net)在这个函数中讨论的问题。问题似乎在于wordwrap()如何处理空格。我没有编写我自己的wordwrap()版本,而是发现“break”参数不仅用作插入的字符串,还用于检测现有的换行分隔符(例如,行尾)。如果您能够“规范化”原始字符串中的换行分隔符,则无需尝试解决函数在看似奇怪的位置(例如,紧跟在一个短单词之后)换行的问题。为了让wordwrap()更好地与大多数用例配合使用,我快速地进行了如下操作

<?php
$break
= strpos( $content, "\r" ) === false ? "\n" : "\r\n";
$content = wordwrap( $content, 78, $break );
?>

如果我的强迫症发作,我也倾向于规范化多行字符串。通常,您会在将其发送到wordwrap()之前执行此转换。

<?php
//快速简单,但会破坏旧式Mac行尾
$content = str_replace( "\r", '', $content );

//较慢,但适用于所有情况
$content = preg_replace( "/(\r\n|\r)/", "\n", $content );

//现在,wordwrap() 将完全按预期工作
$content = wordwrap( $content, 78, "\n" );
?>
To Top