diff --git a/modules/node/node.module b/modules/node/node.module
index 52e4ed6ae1f..ef78d89dbb2 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -173,19 +173,36 @@ function node_teaser($body, $format = NULL) {
return $body;
}
- // In some cases, no delimiter has been specified (e.g. when posting using
- // the Blogger API). In this case, we try to split at paragraph boundaries.
- // When even the first paragraph is too long, we try to split at the end of
- // the next sentence.
- $breakpoints = array('
' => 4, '
' => 0, '
' => 0, "\n" => 0, '. ' => 1, '! ' => 1, '? ' => 1, '。' => 3, '؟ ' => 1);
- foreach ($breakpoints as $point => $charnum) {
- if ($length = strpos($body, $point, $size)) {
- return substr($body, 0, $length + $charnum);
+ // The teaser may not be longer than maximum length specified. Initial slice.
+ $teaser = truncate_utf8($body, $size);
+ $position = 0;
+ // Cache the reverse of the teaser.
+ $reversed = strrev($teaser);
+
+ // In some cases, no delimiter has been specified. In this case, we try to
+ // split at paragraph boundaries.
+ $breakpoints = array('' => 0, '
' => 6, '
' => 4, "\n" => 1);
+ // We use strpos on the reversed needle and haystack for speed.
+ foreach ($breakpoints as $point => $offset) {
+ $length = strpos($reversed, strrev($point));
+ if ($length !== FALSE) {
+ $position = - $length - $offset;
+ return ($position == 0) ? $teaser : substr($teaser, 0, $position);
}
}
- // If all else fails, we simply truncate the string.
- return truncate_utf8($body, $size);
+ // When even the first paragraph is too long, we try to split at the end of
+ // the last full sentence.
+ $breakpoints = array('. ' => 1, '! ' => 1, '? ' => 1, '。' => 0, '؟ ' => 1);
+ $min_length = strlen($reversed);
+ foreach ($breakpoints as $point => $offset) {
+ $length = strpos($reversed, strrev($point));
+ if ($length !== FALSE) {
+ $min_length = min($length, $min_length);
+ $position = 0 - $length - $offset;
+ }
+ }
+ return ($position == 0) ? $teaser : substr($teaser, 0, $position);
}
/**