diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 4a9c1539593..867464fcc76 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -8850,7 +8850,7 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') { global $CFG; // if the plain text is shorter than the maximum length, return the whole text - if (strlen(preg_replace('/<.*?>/', '', $text)) <= $ideal) { + if (textlib::strlen(preg_replace('/<.*?>/', '', $text)) <= $ideal) { return $text; } @@ -8858,7 +8858,7 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') { // and only tag in its 'line' preg_match_all('/(<.+?>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER); - $total_length = strlen($ending); + $total_length = textlib::strlen($ending); $truncate = ''; // This array stores information about open and close tags and their position @@ -8877,19 +8877,19 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') { } else if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) { // record closing tag $tagdetails[] = (object)array('open'=>false, - 'tag'=>strtolower($tag_matchings[1]), 'pos'=>strlen($truncate)); + 'tag'=>textlib::strtolower($tag_matchings[1]), 'pos'=>textlib::strlen($truncate)); // if tag is an opening tag (f.e. ) } else if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) { // record opening tag $tagdetails[] = (object)array('open'=>true, - 'tag'=>strtolower($tag_matchings[1]), 'pos'=>strlen($truncate)); + 'tag'=>textlib::strtolower($tag_matchings[1]), 'pos'=>textlib::strlen($truncate)); } // add html-tag to $truncate'd text $truncate .= $line_matchings[1]; } // calculate the length of the plain text part of the line; handle entities as one character - $content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $line_matchings[2])); + $content_length = textlib::strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $line_matchings[2])); if ($total_length+$content_length > $ideal) { // the number of characters which are left $left = $ideal - $total_length; @@ -8900,14 +8900,14 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') { foreach ($entities[0] as $entity) { if ($entity[1]+1-$entities_length <= $left) { $left--; - $entities_length += strlen($entity[0]); + $entities_length += textlib::strlen($entity[0]); } else { // no more characters left break; } } } - $truncate .= substr($line_matchings[2], 0, $left+$entities_length); + $truncate .= textlib::substr($line_matchings[2], 0, $left+$entities_length); // maximum length is reached, so get off the loop break; } else { @@ -8924,21 +8924,21 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') { // if the words shouldn't be cut in the middle... if (!$exact) { // ...search the last occurence of a space... - for ($k=strlen($truncate);$k>0;$k--) { - if (!empty($truncate[$k]) && ($char = $truncate[$k])) { - if ($char == '.' or $char == ' ') { + for ($k=textlib::strlen($truncate);$k>0;$k--) { + if ($char = textlib::substr($truncate, $k, 1)) { + if ($char === '.' or $char === ' ') { $breakpos = $k+1; break; - } else if (ord($char) >= 0xE0) { // Chinese/Japanese/Korean text - $breakpos = $k; // can be truncated at any UTF-8 - break; // character boundary. + } else if (strlen($char) > 2) { // Chinese/Japanese/Korean text + $breakpos = $k+1; // can be truncated at any UTF-8 + break; // character boundary. } } } if (isset($breakpos)) { // ...and cut the text in this position - $truncate = substr($truncate, 0, $breakpos); + $truncate = textlib::substr($truncate, 0, $breakpos); } } diff --git a/lib/simpletest/testmoodlelib.php b/lib/simpletest/testmoodlelib.php index 575238fb94c..3a2bd3e001d 100644 --- a/lib/simpletest/testmoodlelib.php +++ b/lib/simpletest/testmoodlelib.php @@ -953,6 +953,37 @@ class moodlelib_test extends UnitTestCase { $text = "

123456789

";//a string with no convenient breaks $this->assertEqual("

12345...

", shorten_text($text, 8)); + + // ==== this must work with UTF-8 too! ====== + + // text without tags + $text = "Žluťoučký koníček přeskočil"; + $this->assertEqual($text, shorten_text($text)); // 30 chars by default + $this->assertEqual("Žluťoučký koníče...", shorten_text($text, 19, true)); + $this->assertEqual("Žluťoučký ...", shorten_text($text, 19, false)); + + $text = "

Žluťoučký koníček přeskočil potůček

"; + $this->assertEqual($text, shorten_text($text, 60)); + $this->assertEqual("

Žluťoučký koníček ...

", shorten_text($text, 21)); + $this->assertEqual("

Žluťoučký koníče...

", shorten_text($text, 19, true)); + $this->assertEqual("

Žluťoučký ...

", shorten_text($text, 19, false)); + + // Japanese + $text = '言語設定言語設定abcdefghijkl'; + $this->assertEqual($text, shorten_text($text)); // 30 chars by default + $this->assertEqual("言語設定言語...", shorten_text($text, 9, true)); + $this->assertEqual("言語設定言語...", shorten_text($text, 9, false)); + $this->assertEqual("言語設定言語設定ab...", shorten_text($text, 13, true)); + $this->assertEqual("言語設定言語設定...", shorten_text($text, 13, false)); + + // Chinese + $text = '简体中文简体中文abcdefghijkl'; + $this->assertEqual($text, shorten_text($text)); // 30 chars by default + $this->assertEqual("简体中文简体...", shorten_text($text, 9, true)); + $this->assertEqual("简体中文简体...", shorten_text($text, 9, false)); + $this->assertEqual("简体中文简体中文ab...", shorten_text($text, 13, true)); + $this->assertEqual("简体中文简体中文...", shorten_text($text, 13, false)); + } function test_usergetdate() {