note 88908 deleted from function.substr by danbrown
| From: | danbrown@php.net | Date: | Thu, 12 Feb 2009 21:22:31 +0000 |
| Subject: | note 88908 deleted from function.substr by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-150591@lists.php.net to get a copy of this message | ||
Note Submitter: alex at sirensclef dot com
----
Here's a quick and dirty function to cut text after the specified number of words, but accounts
for XHTML strings. For example:
echo summarize('<div><p>This is a test of the summarize
function.</p></div><div>This is something else.</div>',7);
gives: <div><p>This is a test of the summarize...</p></div>
Obviously not something you want to overuse for performance reasons, but there's a fast path
for strings that don't contain tags and therefore don't need the extra work.
function summarize($str,$limit) { // summarize text up to $limit words, compatible with XHTML
strings
static $dom;
static $limit_reached;
static $word_count;
if (is_scalar($str) && strpos($str,'<')===false) return sizeof(explode('
',$str)>$limit) ? implode(' ',array_slice(explode('
',$str),0,$limit)).'...' : $str; // if string does not contain any tags, do a regular
word trim
if (is_scalar($str)) { // if this is the first call
$dom=new DOMDocument; // create a dom document
if (!@$dom->loadXML('<root>'.$str.'</root>')) return $str; //
try to load the string, returning the original string if failed
$word_count=0; // init word counter
$limit_reached=false; // init limited reached flag
};
if (is_object($str)) {$node=$str;} // if this is a recursive call, used the passed node
else $node=$dom->documentElement; // else use the root element
foreach($node->childNodes as $child) if ($child->nodeType==3) { // loop through child text
nodes
if ($limit_reached) {$node->replaceChild($dom->createTextNode('%removed_node%'),
$child);} // remove all nodes after limit reached
else { // else if limit has not been reached
$words=explode(' ',$child->nodeValue); // create array of words in this node
$count=sizeof($words); // get number of words in this node
if ($word_count+$count>$limit) { // if addition of these words passes the limit
$words=implode(' ',array_slice($words,0,$limit-$word_count)); // create truncated
replacement content
$node->replaceChild($dom->createTextNode($words.'...'),$child); // swap in
replacement content
$limit_reached=true; // flag limit as reached
}
else $word_count+=$count; // else increment the word count and move on to the next node
};
}
else if ($child->hasChildNodes()) summarize($child,$limit); // else if non-text node with
children met, walk it recursively
$output=''; // init output
if (is_scalar($str)) { // if this is the first call
$xpath=new DOMXPath($dom); // create xpath object
foreach($xpath->query('//*[.="%removed_node%"]') as $empty_node)
$empty_node->parentNode->removeChild($empty_node); // remove all empty nodes
foreach($node->childNodes as $child) $output.=$dom->saveXML($child); // add remaining content
to output
unset($dom);
$limit_reached=false;
$word_count=0;
};
return $output;
}