Anyone attempting to write a text email client should be aware of the following:
<?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
?>
Subsequent uses of wordwrap() on already wrapped text will take the end-of-line characters into account when working out line length, thus reading each line that just fit nicely the first time around as being one character too long the second. This can be a problem when preparing a text email that contains (eg.) a forwarded email which has already been word-wrapped.
Solutions below which explode() the text on end-of-lines and wordwrap() the resulting strings separately take care of this nicely.
wordwrap
(PHP 4 >= 4.0.2, PHP 5)
wordwrap — Zawija łańcuch znaków po podanej liczbie znaków używając znaku łamania łańcucha.
Opis
Zwraca łańcuch str zawinięty w kolumny o odpowiedniej ilości znaków określonej przez opcjonalny parametr szerokość . Linia jest łamana przy użyciu (opcjonalnego)parametru break .
wordwrap() będzie automatycznie zawijał kolumny co 75 znaków używając '\n' (nowa linia) jeżeli szerokość lubbreak nie zostaną podane.
Jeżeli cut jest ustawiony na TRUE, łańcuch jest zawsze łamany w określonej szerkości. Gdy mamy wyraz, który jest dłuższy od podanej szerokości, zostanie on przełamany. (Zobacz drugi przykład).
Informacja: Parametr opcjonalny cut został dodany w PHP 4.0.3
Example #1 wordwrap() przykład
<?php
$tekst = "Szybki, brązowy lis przeskoczył nad leniwym psem.";
$nowytekst = wordwrap($tekst, 20, "<br />\n");
echo $nowytekst;
?>
Ten przykład powinien wyświetlić:
Szybki, brązowy lis <br /> przeskoczył nad <br /> leniwym psem
Example #2 wordwrap() przykład
<?php
$tekst = "Bardzo długie słooooooooooowo.";
$nowytekst = wordwrap($tekst, 8, "\n", true);
echo "$newtext\n";
?>
Ten przykład powinien wyświetlić:
Bardzo długie słoooooo ooooowo.
Patrz również nl2br() i chunk_split().
wordwrap
16-Sep-2008 02:17
31-Aug-2008 04:21
This should wrap long lines of code, maintaining the proper level of indentation, plus an extra tab to indicate it's been wrapped.
<?php
function codewrap($code, $maxLength = 80)
{
$lines = explode("\n", $code);
$count = count($lines);
for($i=0; $i<$count; ++$i) {
preg_match('`^\s*`', $code, $matches);
$lines[$i] = wordwrap($lines[$i], $maxLength, "\n$matches[0]\t");
}
return implode("\n", $lines);
}
?>
28-May-2008 02:56
I needed an UTF8/Unicode compatible wordwrap with the same features.
As i searched the internet several times, and havent found anything. I created one my self.
<?php
public static function utf8Wordwrap($str, $width=75, $break="\n", $cut=false)
{
$splitedArray = array();
$lines = explode("\n", $str);
foreach ($lines as $line) {
$lineLength = strlen($line);
if ($lineLength > $width) {
$words = explode("\040", $line);
$lineByWords = '';
$addNewLine = true;
foreach ($words as $word) {
$lineByWordsLength = strlen($lineByWords);
$tmpLine = $lineByWords.((strlen($lineByWords) !== 0) ? ' ' : '').$word;
$tmplineByWordsLength = strlen($tmpLine);
if ($tmplineByWordsLength > $width && $lineByWordsLength <= $width && $lineByWordsLength !== 0) {
$splitedArray[] = $lineByWords;
$lineByWords = '';
}
$newLineByWords = $lineByWords.((strlen($lineByWords) !== 0) ? ' ' : '').$word;
$newLineByWordsLength = strlen($newLineByWords);
if ($cut && $newLineByWordsLength > $width) {
for ($i = 0; $i < $newLineByWordsLength; $i = $i + $width) {
$splitedArray[] = mb_substr($newLineByWords, $i, $width);
}
$addNewLine = false;
} else {
$lineByWords = $newLineByWords;
}
}
if ($addNewLine) {
$splitedArray[] = $lineByWords;
}
} else {
$splitedArray[] = $line;
}
}
return implode($break, $splitedArray);
}
?>
Hope someone else can use this also.
(Also all improvements are welcome)
25-Apr-2008 11:56
I wanted something that would word wrap just one word. People were doing ffffffffffffffffff in my comments page on my site, annoyingly stretching the page. but I didn't want to wrap at a certain fixed length, just wanted to break up words like that only. Here's what I came up with if anyone wants it.
<?php
function one_wordwrap($string,$width){
$s=explode(" ", $string);
foreach ($s as $k=>$v) {
$cnt=strlen($v);
if($cnt>$width) $v=wordwrap($v, $width, "<br />", true);
$new_string.="$v ";
}
return $new_string;
}
?>
21-Apr-2008 03:40
This function can be useful for wrap string by specify chars, not only space char.
<?php
/**
* Wrap string by specify chars
*
* @param string $strForWrap
* @param integer $maxLength
* @param string $breakChar
* @param array $wrapChars
*
* @author Ivan Chura
* @since 21.04.2008
* @return string
**/
function wordwrapBySpecifyChars($strForWrap, $maxLength = 80, $breakChar = "\n", $wrapChars = array(",", ";" ))
{
$newStr = null;
$length_of_string = strlen($strForWrap);
if ($length_of_string <= $maxLength)
{
return $strForWrap;
}
$count_of_string = 1;
$wait_new_line = false;
for($i=0; $i<$length_of_string; $i++)
{
if ( $count_of_string*$maxLength == $i || $wait_new_line)
{
if (in_array($strForWrap{$i}, $wrapChars ) )
{
$count_of_string ++;
$newStr .= $strForWrap{$i}.$breakChar;
$wait_new_line = false;
}
else
{
$newStr .= $strForWrap{$i};
$wait_new_line = true;
}
}
else
{
$newStr .= $strForWrap{$i};
}
}
return $newStr;
}
?>
17-Apr-2008 11:41
These functions let you wrap strings comparing to their actual displaying width of proportional font. In this case Arial, 11px. Very handy in some cases since CSS3 is not yet completely supported. 100 strings = ~5 ms
My old sheep word wrap function (posted at the bottom of this page, is kinda old dated and this one is faster and more accurate).
<?php
//the width of the biggest char @
$fontwidth = 11;
//each chargroup has char-ords that have the same proportional displaying width
$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);
//how the displaying width are compared to the biggest char width
$chargroup_relwidth[0] = 1; //is char @
$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;
//build fast array
$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];
}
}
//get the display width (in pixels) of a string
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;
}
//truncates a string at a certain displaying pixel width
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 :)
}
?>
17-Apr-2008 12:42
There seems to be a difference between php 5.1 and 5.2 in how wordwrap counts characters (all on 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
09-Apr-2008 12:05
@znupiDONTWANTSPAM69 at gmail dot comBLAH
the layout_wrap function doesn't work as I expected. Following is my version. It may consume more resource but gives solid result:
<?php
function longword_break($str, $i) {
if ((empty($str))||(strlen($str)<$i)){
return $str;
}
$words_arr = explode(' ', $str);
foreach ($words_arr as &$word){
$br_word = explode("\n", $word);
//Process some run-in words conected by "\n"
foreach ($br_word as &$r_word){
$j=$i;
while($j < strlen($r_word)) {
$r_word = substr($r_word, 0, $j) . ' '. substr($r_word, $j);
$j+= ($i +1);
}
}
$word =implode("\n", $br_word);
unset($r_word);
}
unset($word);
$str = implode(' ',$words_arr);
//return nl2br(wordwrap($str, $i,"\n", true));
//return nl2br($str);
return $str;
}
// Some test:
$str = "This is 0123456789
aaaaaa ttttttttttttttttttttt
ccc gggggggggg";
$str1 = "aaaaaaaaaaatessssssssssssssssstxxx";
echo "Orgininal string:<br />" . $str . "<br />";
echo "Layout wrap function: <br />" . layout_wrap($str,5). "<br />";
echo "Long word break function: <br/>" . longword_break($str,5). "<br />";
?>
Output:
Orgininal string:
This is 0123456789 aaaaaa ttttttttttttttttttttt ccc gggggggggg
Layout wrap function:
This is 0123456 789 aaaaaa ttttttt tttt tttt tttt tt ccc ggggggg ggg
<!--Notice some "words" are still longer than 5 characters. /-->
Long word break function:
This is 01234 56789 aaaaa a ttttt ttttt ttttt ttttt t ccc ggggg ggggg
04-Apr-2008 07:15
When using wordwrap() on a long word (an English word), It's best to use "-\n" as the '$string break' argument. Why? Because when you're forcing a cut (as bool TRUE), proper English is to include the hyphen to let the reader know that a certain word is being continued on the next line. A good example would be like: http://www.codehelpers.com/Worlds%20Longest%20English%20Word.php
<?php
echo wordwrap($word, 100, "-\n", true);
?>
24-Feb-2008 06:05
If you are dealing with strings that may be very long and without spaces, but at the same time may be very long WITH spaces and you don't want the ones without spaces ruining your HTML+CSS layout, here's a function that adds a space (" ") after every $i characters, if no space is found until that character, so the browser will automatically wrap the text:
<?php
function layout_wrap($str, $i) {
$j = $i;
while ($i < strlen($str)) {
if (strpos($str, ' ', $i-$j+1) > $i+$j || strpos($str, ' ', $i-$j+1) === false) {
$str = substr($str, 0, $i) . ' ' . substr($str, $i);
}
$i += $j;
}
return $str;
}
?>
Hope this helps someone :-)
19-Feb-2008 10:21
I wrote a justification function for a project of mine. It uses the wordwrap function and provides four justification options:
* Left; typically, the leftmost words receive the most padding
* Right; vice versa; the rightmost words receive the most padding
* Both; tries to evenly distribute the padding among leftmost and rightmost words
* Average; most complicated, uses an average of the three previous algorithms. I'd say this one produces the best result as it's more distributed in the center.
It does not justify the last line.
<?php
define('JPAD_LEFT', 1); // More spaces are added on the left of the line
define('JPAD_RIGHT', 2); // More spaces are added on the right of the line
define('JPAD_BOTH', 4); // Tries to evenly distribute the padding
define('JPAD_AVERAGE', 8); // Tries to position based on a mix of the three algorithms
function justify($input, $width, $mode = JPAD_AVERAGE)
{
// We want to have n characters wide of text per line.
// Use PHP's wordwrap feature to give us a rough estimate.
$justified = wordwrap($input, $width, "\n", false);
$justified = explode("\n", $justified);
// Check each line is the required width. If not, pad
// it with spaces between words.
foreach($justified as $line)
{
if(strlen($line) != $width)
{
// Split by word, then glue together
$words = explode(' ', $line);
$diff = $width - strlen($line);
while($diff > 0)
{
// Process the word at this diff
if ($mode == JPAD_BOTH) $words[$diff / count($words)] .= ' ';
else if($mode == JPAD_AVERAGE)
$words[(($diff / count($words)) +
($diff % count($words)) +
(count($words) - ($diff % count($words))))
/ 3] .= ' ';
else if($mode == JPAD_LEFT) $words[$diff % count($words)] .= ' ';
else if($mode == JPAD_RIGHT) $words[count($words) - ($diff % count($words))] .= ' ';
// Next diff, please...
$diff--;
}
}
else
{
$words = explode(' ', $line);
}
$final .= implode(' ', $words) . "\n";
}
// Return the final string
return $final;
}
?>
Examples of output for the average algorithm:
Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id
est laborum.
(50 characters wide)
27-Jan-2008 03:35
This function will provide word-wrap functionality to Firefox (most other browsers have a CSS alternative) by using a zero-width character between every character of any word that goes past the limited size.
<?php
/**
* @desc Wraps a string using a zero-width character between each character of any word past the size limit.
* @param string String to wrap
* @param int Word length limit
*
* @return string Cut string
*/
function cut_word($txt, $where=12) {
if (empty($txt)) return false;
for ($c = 0, $a = 0, $g = 0; $c<strlen($txt); $c++) {
$d[$c+$g]=$txt[$c];
if ($txt[$c]!=" ") $a++;
else if ($txt[$c]==" ") $a = 0;
if ($a>$where) {
$g++;
$d[$c+$g]="​";
}
}
return implode("", $d);
}
?>
15-Jan-2008 01:42
<?php
#for those who don't like word-wrap
function ($string, $max_length) {
$a_string = explode(" ",$string);
foreach ($a_string as $value)
{
if (strlen($value) > $max_length)
{
$length = strlen($value);
$repeats = $length / $max_length;
for ($i=0; $i<$repeats; $i++)
{
$str = substr ($value,($i*$max_length),$max_length);
print "<font color=red>".$str."</font><br />";
}
} else {
print $value."<br />";
}
}
}
?>
30-Oct-2007 11:33
<?php
function strwidth($s){
/*
put some fix for ambiguous width hese
*/
$ret = mb_strwidth($s, 'UTF-8');
return $ret;
}
function mb_wordwrap($str, $wid, $tag){
$pos = 0;
$tok = array();
$l = mb_strlen($str, 'UTF-8');
if($l == 0){
return '';
}
$flag = false;
$tok[0] = mb_substr($str, 0, 1, 'UTF-8');
for($i = 1 ; $i < $l ; ++$i){
$c = mb_substr($str, $i, 1, 'UTF-8');
if(!preg_match('/[a-z\'\"]/i',$c)){
++$pos;
$flag = true;
}elseif($flag){
++$pos;
$flag = false;
}
$tok[$pos] .= $c;
}
$linewidth = 0;
$pos = 0;
$ret = array();
$l = count($tok);
for($i = 0 ; $i < $l ; ++$i){
if($linewidth + ($w = strwidth($tok[$i])) > $wid){
++$pos;
$linewidth = 0;
}
$ret[$pos] .= $tok[$i];
$linewidth += $w;
}
return implode($tag, $ret);
}
?>
25-Oct-2007 08:12
Disregard my note from below, since the function only works for utf8 strings that can be encoded into ISO-8859-1.
25-Oct-2007 06:36
Wordwrap for utf8. Easy to understand and works with the $cut parameter:
<?php
function utf8_wordwrap($str,$width=75,$break="\n", $cut=false){
return utf8_encode(wordwrap(utf8_decode($str), $width, $break, $cut));
}
?>
08-Oct-2007 08:39
<?php
/**
* Wordwrap without unnecessary word splitting using multibyte string functions
*
* @param string $str
* @param int $width
* @param string $break
* @return string
* @author Golan Zakai <golanzakaiATpatternDOTcoDOTil>
*/
function _wordwrap( $str, $width, $break ) {
$formatted = '';
$position = -1;
$prev_position = 0;
$last_line = -1;
/// looping the string stop at each space
while( $position = mb_stripos( $str, " ", ++$position, 'utf-8' ) ) {
if( $position > $last_line + $width + 1 ) {
$formatted.= mb_substr( $str, $last_line + 1, $prev_position - $last_line - 1, 'utf-8' ).$break;
$last_line = $prev_position;
}
$prev_position = $position;
}
/// adding last line without the break
$formatted.= mb_substr( $str, $last_line + 1, mb_strlen( $str ), 'utf-8' );
return $formatted;
}
?>
24-Sep-2007 06:52
luismorrison's function will split a string into a first and second line *only*. If your string is 100 characters long and you wrap at 30 characters you will end up with 30 chars on line 1 and 70 on line 2.
I've included an English translation here for reference as I was going round the bend trying to figure it out in Spanish! :)
<?php
function splitstroverflow($chain,$length) {
$pri_line = array();
$seg_line = array();
$words = explode(" ",trim($chain));
for ($i = 0; $i < count($words); $i++) {
$sum += strlen($words[$i])+1;
if ($sum >= $length) $seg_line[] = $words[$i] . " ";
else $pri_line[] = $words[$i] . " ";
}
for ($i = 0; $i < count($pri_line); $i++)
$lines[0] .= $pri_line[$i];
for ($i = 0; $i < count($seg_line); $i++)
$lines[1] .= $seg_line[$i];
return $lines;
}
?>
16-Aug-2007 08:21
i wrote this by mistake because i didn't know that the same function already exists in PHP.. well shit happens, its quite simple but maybe this will help you someday in your project. The difference is that the one i wrote, called 'splitstroverflow()', cuts given string and parses into arrays to do whatever you like with them.
<?php
function splitstroverflow($cadena,$longitud) {
$pri_renglon = array();
$seg_renglon = array();
$palabras = explode(" ",trim($cadena));
for ($i = 0; $i < count($palabras); $i++) {
$sum += strlen($palabras[$i])+1;
if ($sum >= $longitud) $seg_renglon[] = $palabras[$i] . " ";
else $pri_renglon[] = $palabras[$i] . " ";
}
for ($i = 0; $i < count($pri_renglon); $i++)
$renglones[0] .= $pri_renglon[$i];
for ($i = 0; $i < count($seg_renglon); $i++)
$renglones[1] .= $seg_renglon[$i];
return $renglones;
}
?>
Usage:
<?php
splitstroverflow(str longString,int lenght);
$myrow = splitstroverflow("This is my long long long string",18);
// the array counts 2 elements
// Array
// (
// [0] => "This is my long"
// [1] => "long long string"
// )
?>
29-Jun-2007 12:11
If your string has some html entities, then it might split one in half. e.g.
<?php
/*
Outputs (Renders):
Préf&-
eacute;rence-
s e-mails
*/
echo wordwrap("Préférences e-mails");
?>
To solve this, you can use the following function:
<?php
function wordwrap2( $str, $width = 75, $break = '\n', $cut = true ) {
$str = html_entity_decode( $str ); //first decode
$out = wordwrap( $str, $width, $break, $cut ); //now wordwrap
$out = htmlentities( $out ); //re-encode the entities
$out = str_replace( htmlentities( $break ), $break, $out ); //put back the break
return $out;
}
?>
16-May-2007 07:53
<?php
########################################
# Break long words with out cutting HTML tags.
########################################
/* Break Long Words (string, int, char) */
function breakLongWords($str, $maxLength, $char){
$wordEndChars = array(" ", "\n", "\r", "\f", "\v", "\0");
$count = 0;
$newStr = "";
$openTag = false;
for($i=0; $i<strlen($str); $i++){
$newStr .= $str{$i};
if($str{$i} == "<"){
$openTag = true;
continue;
}
if(($openTag) && ($str{$i} == ">")){
$openTag = false;
continue;
}
if(!$openTag){
if(!in_array($str{$i}, $wordEndChars)){//If not word ending char
$count++;
if($count==$maxLength){//if current word max length is reached
$newStr .= $char;//insert word break char
$count = 0;
}
}else{//Else char is word ending, reset word char count
$count = 0;
}
}
}//End for
return $newStr;
}
?>
27-Mar-2007 05:36
Improved version of egyptechno[at]gmail.com's wordCut.
In this improved function, the length of $sMessage is taken into consideration while cutting the text, so the returned string is never longer than $iMaxLength. Besides that, whole words are cut as well.
<?php
/**
* function wordCut($sText, $iMaxLength, $sMessage)
*
* + cuts an wordt after $iMaxLength characters
*
* @param string $sText the text to cut
* @param integer $iMaxLength the text's maximum length
* @param string $sMessage piece of text which is added to the cut text, e.g. '...read more'
*
* @returns string
**/
function wordCut($sText, $iMaxLength, $sMessage)
{
if (strlen($sText) > $iMaxLength)
{
$sString = wordwrap($sText, ($iMaxLength-strlen($sMessage)), '[cut]', 1);
$asExplodedString = explode('[cut]', $sString);
echo $sCutText = $asExplodedString[0];
$sReturn = $sCutText.$sMessage;
}
else
{
$sReturn = $sText;
}
return $sReturn;
}
?>
19-Dec-2006 03:00
The main concern when you have a text in a cell is for long words that drags the cell margins. This function will break words in a text that have more then $nr characters using the "-" char.
<?php
function processtext($text,$nr=10)
{
$mytext=explode(" ",trim($text));
$newtext=array();
foreach($mytext as $k=>$txt)
{
if (strlen($txt)>$nr)
{
$txt