Forum Moderators: coopster
For example, the string "obfuscation in the skies to fly kites to space" broken into 2 lines should become
obfuscation in the skies
to fly kites to space
or if broken into 3 lines should become
obfuscation in
the skies to fly
kites to space
I can't simply count the words and split those equally because a long word (obfuscation) cannot count the same as a short word (to).
So, I wrote a script that takes the character length of the string, the expected character length of each line, then loops through an array of positions of spaces in the original string to put the right words in the right line. This method felt right at the time. :)
It works for the sample string above when instructed to break into 4 or 5 lines, but does strange things with other line amounts. (And will surely fail regularly when dealing with user input.)
My fingertips and forehead are bleeding from all the banging against keyboards and walls, so if anyone can take a look at this code or just recommend a better way, I could really use the help.
<?php
$str = "obfuscation in the skies to fly kites to space";
//works for 4 and 5 lines, nothing else
$numlines = 4;
$strarray = explode(' ',$str);
$strposarray = strpos_array($str,' ');
$strlength = strlen($str);
$halfway = floor($strlength / $numlines);
print_r($strarray);
echo '<hr />';
print_r($strposarray);
print '<p>('.$strlength.') Nearest space every '.$halfway.' characters</p>';
for ($n=1; $n<=$numlines; $n++){
echo '<p>'.$n.'';
for ($i=1; $i<(count($strposarray)); $i++){
if ($breakpoint[$n-1]<=($i-1)) {
$line[$n] .= ($strarray[$i-1].' ');
}
if ($n==$numlines){
$line[$n] .=
($strarray[($i+$breakpoint[$n-1]-1)].' ');
} else if ($strposarray[$i]>=($halfway*$n)){
$breakpoint[$n] = $i;
echo ' -> '.$i.'</p>';
break;
}
}
}
echo '<hr />';
print_r($breakpoint);
echo '<hr />';
print_r($line);
function strpos_array($haystack, $needle){
$kill = 0; // Kills while loop when changed
$offset = 0; // Offset for strpos()
$i = 0; // Counter, not iterator
while ($kill === 0) {
$i++;
$result = strpos($haystack, $needle, $offset);
if ($result === FALSE) { // If result is false (no more instances found), kill the while loop
$kill = 1;
} else {
$array[$i] = $result; // Set array
$offset = $result + 1; // Offset is set 1 character after previous occurence
}
}
return $array;
}
?>
function returnSplit($str,$lines,$delimiter,$array=false){
$strlength = strlen($str);
$halfway = floor($strlength / $lines);
if ($array){
$result = explode($delimiter,wordwrap($str,$halfway,$delimiter));
} else {
$result = wordwrap($str,$halfway,$delimiter);
}
return $result;
}
print_r(returnSplit($str,4,"<br />\r",true));
I was a bit intrigued when I first seen this thread a couple of days ago. I took a moment to look at it today and from the best I can understand of it ... it won't work the way you think/want/plan.
wordwrap() will always try to split the string based on the width parameter and sentences may have variable length words. This means you cannot specify how many lines are going to be returned, it just won't do what you expect. If you do indeed want to limit the amount of lines though you could split the string into an array and chunk it back together, lopping the leftovers into the last line:
function returnSplit($str, $lines, $delimiter, $array=false)
{
$strlength = strlen($str);
$wrappoint = floor($strlength/($lines));
$newstring = array_chunk(explode($delimiter, wordwrap($str, $wrappoint, $delimiter)), $lines);
//print "$strlength\n$wrappoint\n"; print_r($newstring);
if (isset($newstring[1])) {
for ($i=1; $i<=count($newstring); $i++) {
$newstring[0][$lines-1] .= ' ' . implode(' ', $newstring[$i]);
unset($newstring[$i]);
}
}
return ($array)? $newstring[0] : implode($delimiter, $newstring[0]);
}
Thanks coopster!
is there a reason you must have it divided *somewhat* evenly over a predetermined number of lines?
I'm working on a (quickly becoming massive) GD image generation project and there are a number of instances where variable length user input text is drawn onto multiple lines. Multiple lines of centered text just look better if there's the same amount of text on each line. So, I need to split input to send it to the imagettftext() function for each line.
I suppose I *could* have written it so the user entered text into a textarea and then split on the line breaks, but the decision was made to *not* put that responsibility on the user.
"to to fiver 1 four to to four to to to four to tre tre to seventy tre to four tre fiver tre to four fiver sixxer to tre fiver to four sixxer basetenner sixxer eightter fiver tre seventy eightter"
All the lines look great until the last line which ends up with "basetenner sixxer eightter fiver tre seventy eightter"
So, I changed the floor() to a ceil() and it now produces "sixxer eightter fiver tre seventy eightter" as the last line and seems to do better weighting the words evenly, top to bottom. But, having the last line contain such a disparate quantity of the words is not working out. Any ideas?
to to fiver1 four to to
four to to
to four to
tre tre to
seventy tre
to four tre
fiver tre to
four fiver
sixxer to
tre fiver to
four sixxer
basetenner
sixxer
eightter fiver tre seventy eightter
You will probably have to come up with some advanced formula to count words as well as word length and apply a different formula to your logic.
Which I think brings me full circle back to my original "spaghetti code" to solve this problem. Hmm, I think I'll look to managing expectations about this feature. :/