Cb7e457f43aaafeb9975b9da8f209e4a

It returns a string with a certain character limit, but still retaining whole words.
It breaks out of the foreach loop once it has found a string short enough to display, and the character list can be edited.

At the moment it reverses the array and then works through it, effectively going backwards, but would it be better to go forward?

<?php
function word_limiter( $text, $limit = 30, $chars = '0123456789' ) {
    if( strlen( $text ) > $limit ) {
        $words = str_word_count( $text, 2, $chars );
        $words = array_reverse( $words, TRUE );
        foreach( $words as $length => $word ) {
            if( $length + strlen( $word ) >= $limit ) {
                array_shift( $words );
            } else {
                break;
            }
        }
        $words = array_reverse( $words );
        $text = implode( " ", $words ) . '&hellip;';
    }
    return $text;
}

$str = "Hello this is a list of words that is too long";
echo '1: ' . word_limiter( $str );
$str = "Hello this is a list of words";
echo '2: ' . word_limiter( $str );
?>

Refactorings

No refactoring yet !

421453710d51d7daaea8069af0aa4126

DeathfireD

July 31, 2009, July 31, 2009 02:06, permalink

No rating. Login to rate!

So your making a word limit function? Try this. It's probably not the best method but it's short.

function string_limit_words($string, $word_limit) {
   $words = explode(' ', $string);
   return implode(' ', array_slice($words, 0, $word_limit));
}
 
$str_word = "This is a test to see how this function will work.";
$wordlimit = "4";
echo string_limit_words($str_word, $wordlimit);
D0f517950e189ebe69c903a14cf36fab

alex

July 31, 2009, July 31, 2009 06:05, permalink

No rating. Login to rate!

@DeathfireD

I think what you have created isn't exactly what the OP wanted. He wanted a character limiter, but one that preserved all words.

Here is something I wrote ages ago, so not quite sure if the code quality is too good. Could be useful, at least :)

function abbrString($text, $cutOff) {

	
	if (strlen($text) > $cutOff) {
	
		$text = trim(substr($text, 0 ,$cutOff));
		
		$text = explode(' ', $text);
		
		array_pop($text);
		
		$lastWord = end($text);
		
		while ( ! preg_match('@^[a-zA-Z0-9]*$@i', $lastWord)) {
			
			array_pop($text); // clear off non word
			$lastWord = end($text);
		
		}
		
		$text = join(' ', $text);
		
		
		$text . = '&hellip;';
	
	} 
	
	return $text;


}
284f321ba565cc950ef27bd42956928d

Fanis Hatzidakis

July 31, 2009, July 31, 2009 08:14, permalink

No rating. Login to rate!

I like your solution, charliefrancis. The 2 array reversings might seem be inefficient but for small strings are not that expensive.

I edited your function to remove them anyway, using end() and key() to work with the words array from the end. I also took advantage of str_word_count which returns the length of the string until the previous word as a key of each word in the array. Do a print_r(str_word_count($text, 2)) to see this.

I'm also including the solution I've been using which doesn't split into words but instead works on the given text as a string. Here I wanted to avoid regular expressions so I went the long way around, sticking substrings together. This one returns an array with all the split parts instead of just trimming the given string. Should be trivial to modify to do that if needed.

function word_limiter_noreverse($text, $limit = 30, $chars = '0123456789') {

	if (strlen($text) > $limit) {
		
		$words = str_word_count($text, 2, $chars); //gives you an array of length_until_now => next_word
		
		$numberOfWords = count($words); //or count($words)
		$wordIterator = $numberOfWords - 1;
		

		while ($wordIterator > 0) {
			end($words) ; //set the array pointer to the last element (this also returns the word but we don't need it
			$lengthUntilNow = key($words) ;
			if ($lengthUntilNow <= $limit) {
				//now $words up until (not including) the last word has length that is under or at $limit
				array_pop($words); 
				break;
			}
			array_pop($words);
			$wordIterator--;
		}
		
		$text = implode(" ", $words) . '&hellip;';
	}
	return $text;
}


/**
 * Splits a string into multiple parts of <= $maxLength while keeping
 * words intact. The resulting array of parts is trimmed of prefix and suffix spaces
 * 
 * If the message passed does not require splitting it will be returned on its own
 * in an array 
 *
 * @author Fanis Hatzidakis, code@$surname.org
 * 
 * @param string $msg
 * @param int $maxLength
 * @return array of parts the string was split in
 */
function splitStringOnWords($msg, $maxLength) {
	$msg = trim($msg) ;
	$msgLength = mb_strlen($msg);
	
	if ($msgLength <= $maxLength) {
		return array($msg);
	}
	
	//break it in multiple 
	$ret = array();
	
	while (mb_strlen($msg, 'UTF-8') > $maxLength) {
		$temp = mb_substr($msg, 0, $maxLength);
		$msg = mb_substr($msg, $maxLength);
		$nextChar = mb_substr($msg, 0, 1);
		if ($nextChar !== false && $nextChar != ' ') {
			//we split a word in half. Get the left part of the split word and put it back in $msg
			$lastSpace = mb_strrpos($temp, ' ');
			$lastWordLeftFragment = mb_substr($temp, $lastSpace);
			$msg = $lastWordLeftFragment . $msg;
			//now cut it off from our max_msg_length sized txt
			$temp = mb_substr($temp, 0, $lastSpace);
			//remove the ending space
			$ret[] = trim($temp); 
		}
	}
	$ret[] = trim($msg); //remaining msg is under max_msg_length
	return $ret;
}


$lorem300 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse luctus massa sed justo sagittis eget sollicitudin justo ullamcorper. Ut vitae justo libero. Ut in iaculis metus. Vivamus sed nulla libero. Mauris ligula nisl, iaculis in rutrum ut, euismod quis odio. Aliquam vitae felis sed nullam.' ;
$splitWords = splitStringOnWords($lorem300, 60) ;



$resultMsg = 'Split in the following ' . count($splitWords) . ' parts:<br/>' ; 
foreach ($splitWords as $part) {
	$resultMsg .= chr(34) . $part . chr(34) . ' = ' . strlen($part) . ' chars<br/>' ; 
}

echo $resultMsg ;
D41d8cd98f00b204e9800998ecf8427e

Morkai

July 31, 2009, July 31, 2009 17:55, permalink

No rating. Login to rate!

Might want to use prepare_to_trunc() before truncating text.

<?php

function str_trunc($text, $limit, $uniqSeparator = '%%~`~%%')
{
	return strlen($text) <= $limit ? $text : (current(explode($uniqSeparator, wordwrap($text, $limit, $uniqSeparator), 2)) . '&hellip;');
}

function prepare_to_trunc($text)
{
	return preg_replace('/\s{2,}/s', ' ', trim($text));
}

echo "\n", str_trunc('Hello this is a list of words that is too long', 30);
echo "\n", str_trunc('Hello this is a list of words', 30);

?>
Cb7e457f43aaafeb9975b9da8f209e4a

charliefrancis

August 10, 2009, August 10, 2009 16:14, permalink

No rating. Login to rate!

Thanks guys, always good to see people improving my code!

092fc7e05b5d9850d2f4b93bed8cfd70

Ruslanas

December 8, 2009, December 08, 2009 23:41, permalink

No rating. Login to rate!

Not sure which is faster.

<?php
function word_limiter($text, $limit = 30) {
    // short enough?
    if( strlen($text) <= $limit) {
        return $text;
    }
    // check if last word is full
    if( substr($text, $limit, 1) == ' ') {
        return trim( substr($text, 0, $limit));
    }
    // hard cut
    $cut = substr($text, 0, $limit);
    // remove last word
    $words = explode(' ', $cut);
    array_pop($words);
    return implode(' ', $words);
}

$str = "Hello this is a list of words that is too long";
echo '1: ' . word_limiter($str) . "\n";
$str = "Hello this is a list of words";
echo '2: ' . word_limiter($str);
?>
F2adb7ddda04c91ded08d9e9871b1f9e

Connor Williams

December 10, 2011, December 10, 2011 03:09, permalink

No rating. Login to rate!

Hah, Italy protesters rally against Berlusconi

64f462eab1adc57af3ba2adb7ad203e6

Gavin Dimattia

December 14, 2011, December 14, 2011 05:53, permalink

No rating. Login to rate!

Poor news - Syria's 'mutilation mystery' increases...

10e9eb1791db3c2109ac57b87bda6450

Cool Code

January 2, 2012, January 02, 2012 15:59, permalink

No rating. Login to rate!

How can you find the 2 for 1 garlic bread voice chit with regard to lemon fridays?

Ca4d1fed0049d66186cd3c8d4e112736

Eva Jackson

January 4, 2012, January 04, 2012 01:43, permalink

No rating. Login to rate!

Happy New Year for all!

B676560afe7fab2ffb76bed51ef53664

Kayla Espinoza

January 4, 2012, January 04, 2012 22:54, permalink

No rating. Login to rate!

Happy New Year to All!

D749f4bb20a2bbf9039fc2391ff756c2

UK Vouchers

January 12, 2012, January 12, 2012 12:18, permalink

No rating. Login to rate!

How will you receive the 2 for 1 garlic bread voice chit for citrus fridays?

6ccd3e9735a46b65ead654e62915addd

Coupons

January 25, 2012, January 25, 2012 17:51, permalink

No rating. Login to rate!

Decent Airline flight Simulators Around to get 2012 this won't break the bank?

862e023c33d81770c6b9a22592bce7e1

Latest Coupons

Yesterday, February 08, 2012 19:49, permalink

No rating. Login to rate!

How will you deliver joyful 12 months minute card to buddies with myspace?

Your refactoring





Format Copy from initial code

or Cancel