Page 1 of 3

Chopping text question

Posted: Mon Apr 02, 2007 3:04 pm
by Sinemacula
In an earlier thread – viewtopic.php?t=25351 – I found this:
feyd wrote:

Code: Select all

<?php

$text = 'Jack went to the store to get himself a large bottle of whiskey';

preg_match('#^\s*(.{26,}?)\s+.*$#', $text, $match);

var_export($match);

?>
outputs

Code: Select all

array (
0 => 'Jack went to the store to get himself a large bottle of whiskey',
1 => 'Jack went to the store to get',
)
Which almost does exactly what I want...

My problem is that I've set the length to 15, but some of my text items are less than 15 characters long, so they're getting cut off completely.

e.g.

Code: Select all

<?php
$text = 'Personality & Personal Growth'
preg_match('#^\s*(.{15,}?)\s+.*$#s', $book, $match); 
var_export($match);
outputs

Code: Select all

array (0 => 'Personality & Personal Growth',
1 => 'Personality & Personal',)
but

Code: Select all

<?php
$text = 'Testing'
preg_match('#^\s*(.{15,}?)\s+.*$#s', $book, $match); 
var_export($match);
outputs

Code: Select all

array ()
What do I need to change so that when $text is less than the set value in the preg_match statment, the whole $text will be returned?

Thanks,
Scott

Posted: Mon Apr 02, 2007 3:19 pm
by Oren
Please tell us exactly what you want to do, since I've got the feeling that this code is not what you real want.
I think what you really need is substr().

Posted: Mon Apr 02, 2007 3:28 pm
by Sinemacula
I want to have the results from a mysql query displayed such that they will be truncated at 15 characters AND such that if truncation would happen in the middle of a word, it will go to the next space before cutting it off.

So,
  • if $text is less than 15 characters, the whole of $text is displayed
  • if $text is more than 15 characters, it will be truncated at the 15th character
    • BUT, if the 15th character of $text is in the middle of a word, it will go to the next space

Posted: Mon Apr 02, 2007 3:42 pm
by Oren
I don't know, but MySQL might have a built-in function which does exactly this thing for you - if such a function exists, it will most likely be faster than doing it on the PHP side.

Posted: Mon Apr 02, 2007 3:53 pm
by Sinemacula
Well, I think I need to do it with php because it's only the display of the results that I want shortened in one part of a page.

The full code I'm using is:

Code: Select all

$book=$myrow3['title'];
preg_match('#^\s*(.{15,}?)\s+.*$#s', $book, $match); 

echo "<li><a href=\"http://astore.amazon.com/itp-ma4cs-20/detail/".$myrow3['isbn']."\" target=\"iframe\" title=\"".$book."\">".$match[1]."...</a></li>";
So, in this case, it's $book that I want to display only 15 characters of in one place, but I want the whole thing displaying in another place... so I still need to have the whole value of $book available. What I've got there works fine, except for when $book is less than 15 characters long - in which case it displays nothing for $match[1]. :(

Posted: Mon Apr 02, 2007 3:59 pm
by Oren
You said you need the "whole thing" in another page - which means a new query anyway, so my argument still holds :wink:

Posted: Mon Apr 02, 2007 4:15 pm
by Sinemacula
Actually, I need the "whole thing" in another "place" :wink: -- same page, same statement even (notice $book and $match[1]), so only one query (in this particular case, since it's creating a url link, I want the shortened version to display, but the full version as the link title).

Posted: Mon Apr 02, 2007 6:19 pm
by onion2k

Code: Select all

SELECT title, 
SUBSTR(title,1,LOCATE(' ',title,15)) as trimmed_title
FROM `my_table` WHERE 1

Posted: Mon Apr 02, 2007 6:55 pm
by RobertGonzalez
The manual is a wonderful place to learn PHP.

Posted: Mon Apr 02, 2007 9:29 pm
by feyd

Code: Select all

#^\s*(.{15,}?)\s+.*$#s
The code requires a passed string to be 15 characters or more before it will find anything.

It was meant to be used in conjunction with strlen().

Posted: Mon Apr 02, 2007 11:41 pm
by Sinemacula
I tried some of the functions examples in the php manual pages, but they wouldn't work because I'm using it in a recursive section, and I kept getting an error message that I could not "redeclare" the function.

However, I found that adding a strlen() statement did what I need, so I've got:

Code: Select all

$book=$myrow3['title'];
$limit='18';
			
if(strlen($book) > $limit)
{
     preg_match('#^\s*(.{12,}?)\s+.*$#s', $book, $match);
     $trimmed_book = $match[1]."...";
} else {
     $trimmed_book = $book;
}
which appears to be working fine for what I need.

Thanks,
Scott

Posted: Tue Apr 03, 2007 12:28 am
by Sinemacula
Shortly after posting that I'd found a working solution, I had a hunch to try something else... I think this solution is better and solves the actual problem I was having, rather than being a "workaround" that might not work for all scenarios.

Here's what I'm now using, successfully:

Code: Select all

$book=$myrow3['title'];
	preg_match('#^\s*(.{11,}?)\s+.*$#s', $book, $match);
		
	if(strlen($match[1]) > '0')
	{
		$trimmed_book = $match[1]."...";
	} else {
		$trimmed_book = $book;
	}

Posted: Tue Apr 03, 2007 12:46 am
by Kieran Huggins
why not just wordwrap() the text then take the first line... seems much cleaner, and faster to me!

Posted: Tue Apr 03, 2007 10:21 am
by RobertGonzalez
This is really not that hard. In fact, I got this from the manual page that I had linked to in my last post, a few comments down...

Code: Select all

<?php
function truncate_long_string($string, $max_length) {
	if (strlen($string) > $max_length) {
		$string = substr($string, 0, $max_length);

		if (($pos = strrpos($string, ' ')) === false) {
			return substr($string, 0, $max_length) . ' ...';
		}
        
		return substr($string, 0, $pos) . ' ...';
	} else {
		return $string;
	}
}

$test_string = 'If only there were a function that would cut strings down but not cut words in the process.';

/**
 * Outputs: If only there ...
 */
echo truncate_long_string($test_string, 15) . '<br />';

/**
 * Outputs: If only there were a ...
 */
echo truncate_long_string($test_string, 25) . '<br />';

/**
 * Outputs: If only there were a function that ...
 */
echo truncate_long_string($test_string, 40) . '<br />';

/**
 * Outputs: If only there were a function that would cut strings ...
 */
echo truncate_long_string($test_string, 55) . '<br />';

/**
 * Outputs: If only there were a function that would cut strings down but not cut words in the process.
 */
echo truncate_long_string($test_string, 150) . '<br />';
?>

Posted: Tue Apr 03, 2007 2:49 pm
by Sinemacula
Everah wrote:This is really not that hard. In fact, I got this from the manual page that I had linked to in my last post, a few comments down...
Unfortunately, the code you posted, just like the other functions I tried from the manual page you referenced, does not work for my situation... using that code, I get the following error:

Code: Select all

Fatal error: Cannot redeclare truncate_long_string() (previously declared in...
I don't know enough to know if there's a way around that, or a "fix" for such functions such that they can deal with the recursive nature of what I'm doing, but the preg_match code followed by the strlen code as I posted above is working fine.

Now, if I could just figure out the right way to do my mysql query as a JOIN rather than three separate queries ( viewtopic.php?p=370960 ), I'd be set! :D :roll: :wink: