Smarter word-wrap in PHP for long words?
Solution 1
I've had a go at the custom function for this smart wordwrap:
function smart_wordwrap($string, $width = 75, $break = "\n") {
// split on problem words over the line length
$pattern = sprintf('/([^ ]{%d,})/', $width);
$output = '';
$words = preg_split($pattern, $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
foreach ($words as $word) {
if (false !== strpos($word, ' ')) {
// normal behaviour, rebuild the string
$output .= $word;
} else {
// work out how many characters would be on the current line
$wrapped = explode($break, wordwrap($output, $width, $break));
$count = $width - (strlen(end($wrapped)) % $width);
// fill the current line and add a break
$output .= substr($word, 0, $count) . $break;
// wrap any remaining characters from the problem word
$output .= wordwrap(substr($word, $count), $width, $break, true);
}
}
// wrap the final output
return wordwrap($output, $width, $break);
}
$string = 'hello! too long here too long here too heeeeeeeeeeeeeereisaverylongword but these words are shorterrrrrrrrrrrrrrrrrrrr';
echo smart_wordwrap($string, 11) . "\n";
EDIT: Spotted a couple of caveats. One major caveat with this (and also with the native function) is the lack of multibyte support.
Solution 2
How about
$string = "hello! heeeeeeeeeeeeeeereisaverylongword";
$break = 25;
echo implode(PHP_EOL, str_split($string, $break));
Which outputs
hello! heeeeeeeeeeeeeeere
isaverylongword
str_split() converts the string to an array of $break size chunks.
implode() joins the array back together as a string using the glue which in this case is an end of line marker (PHP_EOL) although it could as easily be a '<br/>
'
Solution 3
This is also a solution (for browsers etc.):
$string = 'hello! heeeeeeeeeeeeeeeeeeeeeereisaverylongword';
echo preg_replace('/([^\s]{20})(?=[^\s])/', '$1'.'<wbr>', $string);
It puts a <wbr>
at words with 20 or more characters
<wbr>
means "word break opportunity" so it only breaks if it has to (dictated by width of element/browser/viewer/other). It's invisible otherwise.
Good for fluid/responsive layout where there is no fixed width. And does not wrap odd like php's wordwrap
Solution 4
You can use CSS to accomplish this.
word-wrap: break-word;
That will break the word for you. Here is a link to see it in action:
http://www.css3.info/preview/word-wrap/
Solution 5
This should do the trick...
$word = "hello!" . wordwrap('heeeeeeeeeeeeeeereisaverylongword', 25, '<br />', true);
echo $word;
mowgli
Updated on July 09, 2022Comments
-
mowgli almost 2 years
I'm looking for a way to make word-wrap in PHP a bit smarter. So it doesn't pre-break long words leaving any prior small words alone on one line.
Let's say I have this (the real text is always completely dynamic, this is just to show):
wordwrap('hello! heeeeeeeeeeeeeeereisaverylongword', 25, '<br />', true);
This outputs:
hello!
heeeeeeeeeeeeeeereisavery
longwordSee, it leaves the small word alone on the first line. How can I get it to ouput something more like this:
hello! heeeeeeeeeeee
eeereisaverylongwordSo it utilizes any available space on each line. I have tried several custom functions, but none have been effective (or they had some drawbacks).
-
mowgli about 12 yearsI just used some example words. In real use, the text would be completely dynamic, so I could'nt use that
-
mowgli about 12 yearsI'm not breaking the words for a browser
-
Paul Dessert about 12 yearsNot sure exactly how your trying to do this, but why couldn't you dynamically change this? Just use variables to set your text
-
mowgli about 12 yearsDynamically change what? The text can be anything, any length, any number of words. I don't know what the first word or any word will be ;)
-
Paul Dessert about 12 yearsOh, gotcha. Then, I guess you'd need to create a custom function.
-
mowgli about 12 years;) Do you have an idea how? I know I should probably use some regex, but don't know how to get about it..
-
Paul Dessert about 12 yearsSorry, don't have the time for that right now. :) Someone else might come along and give you more detail... Good luck.
-
zerkms about 12 yearsThe trivial regexp would be: replace
\S{42}
with\\1
(note space in the replacement) -
mowgli about 12 yearswhere does the word wrapping go then? ;)
-
mowgli about 12 yearsWhat does $width = 75 set excactly?
-
cmbuckley about 12 yearsThe function signature is exactly that of wordwrap (without the break parameter), so it sets a default wrap width of 75 characters.
-
Eli about 12 yearsnothing, its just the default values he is using. In case you don't supply your own with of
11
, then75
will be used. -
mowgli about 12 yearsAh ok. Nevermind multibyte support cbuckley ;) Well I don't need it for this anyway
-
Sandeepan Nath almost 12 yearsthis did not work for me. I tried it on a table's td. I applied some
width
under style andword-wrap: break-word;
-
Sandeepan Nath almost 12 yearsIt seems this solution handles both cases - 1. long word with no spaces and 2. long word with spaces. An advantage over @frglps's solution
-
Maelish over 9 yearsIt's 2014 and it still down't work in every browser. Sometimes php covers your butt.
-
LecheDeCrema about 7 yearsyow even it's 2017 this is very helpful! Thanks :)
-
Nicklasos over 5 yearsThank! Works for me! But you should add unicode option to regex: /([^\s]{20})(?=[^\s])/u
-
Vipertecpro about 5 yearsI just made helper function in laravel with your answer thank you so much.