PHP Conference Japan 2024

wordwrap

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

wordwrap將字串換行至指定字元數

說明

wordwrap(
    字串 $string,
    整數 $width = 75,
    字串 $break = "\n",
    布林值 $cut_long_words = false
字串

使用字串換行字元,將字串換行至指定字元數。字串會在空格 (U+0020) 字元之後換行,除非 cut_long_words 設定為 true

參數

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 個註解

17
ju1ius
12 年前
另一個使用正規表示式的 utf-8 安全換行解決方案。
效能相當好,並且以線性時間運作。

<?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。
7
michdingpayc
2 年前
對 10 年前 ju1ius 的 utf-8 安全換行進行修正。
這個版本解決了未將換行符號新增至輸入字串中的第一個和最後一個單字的問題。

<?php
function 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);
}
?>
15
Dave Lozier - dave at fusionbb.com
19 年前
如果您想要斷開長字串但避免斷開 HTML,您可能會覺得這個很有用。 它似乎對我有效,希望它對您也有效。 請享用。 :)

<?php
function 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;
}
?>
12
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;
};

?>
2
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()

希望這對某些人有幫助
1
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 />');

}
//結束函式

?>
1
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);
}
?>
1
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() 時,會將換行符號納入考量,以計算行長度,因此,第一次剛好符合的每一行,第二次都會被讀取為長度多一個字元。當準備包含(例如)已換行的轉寄電子郵件的文字電子郵件時,這可能會是一個問題。

以下將文字以換行符號分解並分別對產生的字串使用 wordwrap() 的解決方案,可以很好地處理這個問題。
0
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;
}

?>
-1
$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 is the reason rules at 10am :)
}
?>
-1
answers at 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 用於命令列,HTML 請使用 '<br/>'。
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
-2
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").' ...'; //返回字串長度減去到最後一個空格的位置,並加上三個點
}
?>

該函數只是簡單地搜尋範圍內的最後一個空格符號,並返回切割到該位置的字串。沒有迭代、沒有正規表示式,也沒有緩衝區溢位。用大量的俄文文本測試過,完美運作。
-3
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;
}
?>
-3
ojs-hp at web dot de
15 年前
在我的函數將 BB-text 轉換為 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;
}
?>
-4
maikuolan at gmail dot com
11 年前
(回覆:kouber at php dot net)。

測試您的函數,我可以確認它有效,而且效果非常好。

但是,打算使用您函數的其他使用者需要注意,如果他們將其與未驗證的資料(例如來自 $_POST、$_GET 等的原始使用者輸入)一起使用,則他們正在建立潛在的攻擊途徑,駭客可以通過包含惡意程式碼的腳本請求加以利用。這是因為您的函數正在將 preg_replace 函數與「e」標誌結合使用(為了允許執行 chunk_split 位),這可能會允許執行任意程式碼。

解決方案:如果 $str 有任何可能包含未驗證的資料(例如原始使用者輸入),請確保在將其發送到 wrap($str,...) 之前對 $str 的內容進行消毒(例如使用 htmlentities/htmlspecialchars/ 等)。

並非批評;我打算使用您的函數,因為我喜歡它。但是,只是在此處發布此說明,以提醒其他可能不了解資料消毒重要性的使用者。
-3
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;
}
-3
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() 的字串來分隔。
-3
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
-5
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