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
longword
See, it leaves the small word alone on the first line.
How can I get it to ouput something more like this:
hello! heeeeeeeeeeee
eeereisaverylongword
So it utilizes any available space on each line. I have tried several custom functions, but none have been effective (or they had some drawbacks).
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.
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/>'
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
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/
This should do the trick...
$word = "hello!" . wordwrap('heeeeeeeeeeeeeeereisaverylongword', 25, '<br />', true);
echo $word;
Related
Update: It seems like it is just a regex problem.
I am trying to remove all extra whitespace, line-breaks, and empty spaces from user story with a function to grab only 100 characters
Issue is although 100 character limit works, the removing of whitespace, linebreaks and empty spaces does not apply:
function aboutme_echo($x, $length)
{
if(strlen($x) <= $length)
{
echo $x;
}
else
{
$y = substr($x,0,$length) . '...';
echo $y;
}
}
aboutme_echo((preg_replace("/\s+/"," ", $aboutme)), 100);
Example String: 🤣🤣🤣WHAT?! That's crazy!
Long story short,
😛😛someone reached out to me who had a pharma virus.
😎I have the opportunity to rebuild their site, but I can't rush the planning and staging, but i...
Something like this maybe?
function cleanExcerpt($string) {
$pattern = '/\s+/';
$replace = ' ';
$cleanstring = trim(preg_replace($pattern,$replace,$string));
return strtok(wordwrap($cleanstring, 100, "...\n"), "\n");
}
To use, you must pass through a string and echo the function like this:
$string = "Example String: 🤣🤣🤣WHAT?! That's crazy! Long story short, 😛😛someone reached ";
echo cleanExcerpt($string);
this is what I try to get:
My longest text to test When I search for e.g. My I should get My longest
I tried it with this function to get first the complete length of the input and then I search for the ' ' to cut it.
$length = strripos($text, $input) + strlen($input)+2;
$stringpos = strripos($text, ' ', $length);
$newstring = substr($text, 0, strpos($text, ' ', $length));
But this only works first time and then it cuts after the current input, means
My lon is My longest and not My longest text.
How I must change this to get the right result, always getting the next word. Maybe I need a break, but I cannot find the right solution.
UPDATE
Here is my workaround till I find a better solution. As I said working with array functions does not work, since part words should work. So I extended my previous idea a bit. Basic idea is to differ between first time and the next. I improved the code a bit.
function get_title($input, $text) {
$length = strripos($text, $input) + strlen($input);
$stringpos = stripos($text, ' ', $length);
// Find next ' '
$stringpos2 = stripos($text, ' ', $stringpos+1);
if (!$stringpos) {
$newstring = $text;
} else if ($stringpos2) {
$newstring = substr($text, 0, $stringpos2);
} }
Not pretty, but hey it seems to work ^^. Anyway maybe someone of you have a better solution.
You can try using explode
$string = explode(" ", "My longest text to test");
$key = array_search("My", $string);
echo $string[$key] , " " , $string[$key + 1] ;
You can take i to the next level using case insensitive with preg_match_all
$string = "My longest text to test in my school that is very close to mY village" ;
var_dump(__search("My",$string));
Output
array
0 => string 'My longest' (length=10)
1 => string 'my school' (length=9)
2 => string 'mY village' (length=10)
Function used
function __search($search,$string)
{
$result = array();
preg_match_all('/' . preg_quote($search) . '\s+\w+/i', $string, $result);
return $result[0];
}
There are simpler ways to do that. String functions are useful if you don't want to look for something specific, but cut out a pre-defined length of something. Else use a regular expression:
preg_match('/My\s+\w+/', $string, $result);
print $result[0];
Here the My looks for the literal first word. And \s+ for some spaces. While \w+ matches word characters.
This adds some new syntax to learn. But less brittle than workarounds and lengthier string function code to accomplish the same.
An easy method would be to split it on whitespace and grab the current array index plus the next one:
// Word to search for:
$findme = "text";
// Using preg_split() to split on any amount of whitespace
// lowercasing the words, to make the search case-insensitive
$words = preg_split('/\s+/', "My longest text to test");
// Find the word in the array with array_search()
// calling strtolower() with array_map() to search case-insensitively
$idx = array_search(strtolower($findme), array_map('strtolower', $words));
if ($idx !== FALSE) {
// If found, print the word and the following word from the array
// as long as the following one exists.
echo $words[$idx];
if (isset($words[$idx + 1])) {
echo " " . $words[$idx + 1];
}
}
// Prints:
// "text to"
I am using PHP to return the user's browser user agent The problem is where I want to print it: I don't want the length to be longer than about 30 characters per line. Is there a way to break the returned variable (from the function that I call to get the string) into substrings of a certain length? And since UA strings are different lengths, I am not sure what to expect.
This is the PHP code where I return the user agent:
function __toString() {
return "Browser Name:
return "Browser Name: {$this->getBrowser()} \n" .
" Browser Version: {$this->getVersion()} \n" .
" Browser User Agent String: {$this->getUserAgent()} \n" .
" Platform: {$this->getPlatform()} ";
}
In particular, this call $this->getUserAgent. I output using this:
<?php require_once('browser.php'); $browser = new Browser(); echo $browser . "\n"; ?>
Right now, the name, version and platform calls output like I want to (because none are anywhere near as long at the UA string).
So in short, how do I split up the returned user string so that it won't exceed a certain number of characters per line? Ideally, I'd like to store them into temporary variables, because I have to add spaces in between the words. For example, where it says "Platform", there are spaces before it, so it lines up vertically with Browser Version, and then spaces so that the result of all the returned strings from the functions line up.
In case anyone wants the Github code for above to see what I am doing, the function calls are in this on lines 339-243, and the echoed results go to this on line 152.
At this point I am very very close
Just need help adding spaces before the wrapped text (see my answer below)
This is what I have right now:
$text1 = $this->getUserAgent();
$UAline1 = substr($text1, 0, 26);
$text2 = $this->getUserAgent();
$towrapUA = str_replace($UAline1, '', $text2);
$wordwrapped = chunk_split($towrapUA, 26, "\n\r");
The only issue at this point it how do I get a constant number of spaces before each of the wrapped code? I need (lets say) 20 spaces before all of the wrapped lines for formatting.
Try this:
$str = chunk_split($string, 30, "\n\r");
// Splits a string after X chars (in this case 30) and adds a line break
You can also try it using regex:
$str = preg_replace("/(.{30})/", "$1\n\r", $string);
Or, as suggested in the comments above, this does the same thing:
$str = wordwrap($string, 30, "<br />\n");
More info:
http://php.net/manual/en/function.chunk-split.php
http://us2.php.net/wordwrap
EDIT:
Based on your edited question, it looks like this is what you're looking for:
$text1 = $this->getUserAgent();
$UAline1 = substr($text1, 0, 26);
$towrapUA = str_replace($UAline1, '', $text1);
$space = str_repeat(' ', 20);
$wordwrapped = wordwrap($towrapUA, 26, "\n");
$wordwrapped = explode("\n", $wordwrapped); // Split at '\n'
$numlines = count($wordwrapped) - 1;
$string = '';
$i = 0;
foreach($wordwrapped as $line) {
if($i < $numlines) {
$string .= $space . $line . "\n\r"; // Add \n\r back in if not last line
} else {
$string .= $space . $line; // If it's the last line, leave off \n\r
}
$i++;
}
echo $string;
I want to display just two lines of the paragraph.
How do I do this ?
<p><?php if($display){ echo $crow->content;} ?></p>
Depending on the textual content you are referring to, you might be able to get away with this :
// `nl2br` is a function that converts new lines into the '<br/>' element.
$newContent = nl2br($crow->content);
// `explode` will then split the content at each appearance of '<br/>'.
$splitContent = explode("<br/>",$newContent);
// Here we simply extract the first and second items in our array.
$firstLine = $splitContent[0];
$secondLine = $splitContent[1];
NOTE - This will destroy all the line breaks you have in your text! You'll have to insert them again if you still want to preserve the text in its original formatting.
If you mean sentences you are able to do this by exploding the paragraph and selecting the first two parts of the array:
$array = explode('.', $paragraph);
$2lines = $array[0].$array[1];
Otherwise you will have to count the number of characters across two lines and use a substr() function. For example if the length of two lines is 100 characters you would do:
$2lines = substr($paragraph, 0, 200);
However due to the fact that not all font characters are the same width it may be difficult to do this accurately. I would suggest taking the widest character, such as a 'W' and echo as many of these in one line. Then count the maximum number of the largest character that can be displayed across two lines. From this you will have the optimum number. Although this will not give you a compact two lines, it will ensure that it can not go over two lines.
This is could, however, cause a word to be cut in two. To solve this we are able to use the explode function to find the last word in the extracted characters.
$array = explode(' ', $2lines);
We can then find the last word and remove the correct number of characters from the final output.
$numwords = count($array);
$lastword = $array[$numwords];
$numchars = strlen($lastword);
$2lines = substr($2lines, 0, (0-$numchars));
function getLines($text, $lines)
{
$text = explode("\n", $text, $lines + 1); //The last entrie will be all lines you dont want.
array_pop($text); //Remove the lines you didn't want.
return implode("<br>", $text); //Implode with "<br>" to a string. (This is for a HTML page, right?)
}
echo getLines($crow->content, 2); //The first two lines of $crow->content
Try this:
$lines = preg_split("/[\r\n]+/", $crow->content, 3);
echo $lines[0] . '<br />' . $lines[1];
and for variable number of lines, use:
$num_of_lines = 2;
$lines = preg_split("/[\r\n]+/", $crow->content, $num_of_lines+1);
array_pop($lines);
echo implode('<br />', $lines);
Cheers!
This is a more general answer - you can get any amount of lines using this:
function getLines($paragraph, $lines){
$lineArr = explode("\n",$paragraph);
$newParagraph = null;
if(count($lineArr) > 0){
for($i = 0; $i < $lines; $i++){
if(isset($lines[$i]))
$newParagraph .= $lines[$i];
else
break;
}
}
return $newParagraph;
}
you could use echo getLines($crow->content,2); to do what you want.
What's the best way to remove the very first line of a text string and then echo the rest in PHP?
For example.
This is the text string:
$t=<<<EOF
First line to be removed
All the rest
Must remain
EOF;
This is the final output:
All the rest
Must remain
If I was working with a file in Bash I could do easily the next:
sed -i~ 1d target-file
Or:
tail -n +2 source-file > target-file
Any ideas?
In alternative to the other answers with either explode & implode or regular expressions, you can also use strpos() and substr():
function stripFirstLine($text) {
return substr($text, strpos($text, "\n") + 1);
}
echo stripFirstLine("First line.\nSecond line.\nThird line.");
Live example: http://codepad.org/IoonHXE7
How about preg_replace:
$text = "First line.\nSecond line.\nThird line.";
echo preg_replace('/^.+\n/', '', $text);
This way you don't need to worry about the case where there is no newline in your file.
http://codepad.org/fYZuy4LS
explode() it on the line breaks into an array, shift() off the first line, and rejoin the rest.
$arr = explode("\n", $t);
array_shift($arr);
echo implode("\n", $arr);
// Prints
// All the rest
// Must remain
If your string is really large, this will use a lot of memory. But if your strings are comparable to your example, it will work fine.
Method 2, using strpos()
echo substr($t, strpos($t, "\n") + 1);
I know it's a late answer, but why wouldn't you just use an explode and limit the number of results
$parts = explode("\n", $test, 2);
//$parts[0] has the first line
//$parts[1] has everything else
I tried all of these, and none seemed to work fast enough with large files (50MB+). Here was the solution I created. In your case, you could omit the echo of the first line.
$fh = fopen($local_file, 'rb');
echo "add\tfirst\tline\n"; // add your new first line.
fgets($fh); // moves the file pointer to the next line.
echo stream_get_contents($fh); // flushes the remaining file.
fclose($fh);
More flexible solution where you can remove num lines from a string str using a seperator and return the rest.
The default seperator is \n. If you want to use a different seperator use a third argument when calling striplines() function.
function striplines($str,$num,$seperator="\n"){
$arr = explode($seperator, $str);
for ($i=0;$i<$num;$i++) array_shift($arr);
return implode($seperator, $arr);
}
//Testcases to remove first two lines
// returns/prints only Third line
echo striplines("First line.\nSecond line.\nThird line.",2);
// returns/prints nothing
echo striplines("First line.\nSecond line.\n",2);
echo striplines("First line.\nSecond line.",2);
echo striplines("First line.\n",2);
echo striplines("First line.",2);
echo striplines("",2);
Return a substring after the first newline-character:
$firstLineRemoved = $subject;
$firstNewlinePosition = strpos($subject, "\n");
if($firstNewlinePosition !== false)
{
$firstLineRemoved = substr($subject, firstNewlinePosition +1);
}
echo $firstLineRemoved;
Edit: Same example as #ComFreek, but with error checking in case there is no new-line character
All the answers are inefficient. There is no need to use any functions to manipulate the string.
$pos = 0;
while ($str[$pos] !== PHP_EOL)
$str[$pos++] = '';
echo $str;
If you are not sure that the string always contains more than one line use this:
if (strpos($str, PHP_EOL))
{
$pos = 0;
while ($str[$pos] !== PHP_EOL)
$str[$pos++] = '';
echo $str;
}