diff --git a/README.md b/README.md index 118df37..93d2946 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,9 @@ A PHP library with a variety of string manipulation functions with multibyte sup * [toTabs](#totabs) * [slugify](#slugify) * [contains](#contains) + * [surround](#surround) + * [insert](#insert) + * [truncate](#truncate) * [Tests](#tests) * [License](#license) @@ -335,12 +338,21 @@ Inserts $substring into $str at the $index provided. S::insert('fòô bà', 'ř', 6, 'UTF-8'); // 'fòô bàř' ``` +##### truncate + +S::truncate(string $str, int $length, [, string $substring = '' [, string $encoding ] ]) + +Truncates the string to a given length, while ensuring that it does not +chop words. If $substring is provided, and truncating occurs, the string +is further truncated so that the substring may be appended without +exceeding the desired length. + +```php +S::truncate('What are your plans today?', 22, '...'); // 'What are your plans...' +``` + ## TODO -**truncate** - -**prune** - **wordWrap** => wordwrap **reverse** => strrev @@ -353,12 +365,10 @@ S::insert('fòô bà', 'ř', 6, 'UTF-8'); // 'fòô bàř' **longestCommonSubstring** -**countChars** => count_chars +**count** => substr_count **wordCount** => str_word_count -**count** => substr_count - **isJson** **isMultibyte** diff --git a/src/Stringy/Stringy.php b/src/Stringy/Stringy.php index 589f607..ef732b2 100644 --- a/src/Stringy/Stringy.php +++ b/src/Stringy/Stringy.php @@ -463,7 +463,7 @@ class Stringy { $str = preg_replace('/[^a-zA-Z\d -]/u', '', self::standardize($str)); $str = self::clean($str); - return self::dasherize(strtolower($str)); + return str_replace(' ', '-', strtolower($str)); } /** @@ -506,15 +506,50 @@ class Stringy { public static function insert($str, $substring, $index, $encoding = null) { $encoding = $encoding ?: mb_internal_encoding(); - if ($index > mb_strlen($str)) + if ($index > mb_strlen($str, $encoding)) return $str; $start = mb_substr($str, 0, $index, $encoding); - $end = mb_substr($str, $index, mb_strlen($str), $encoding); + $end = mb_substr($str, $index, mb_strlen($str, $encoding), $encoding); return $start . $substring . $end; } + /** + * Truncates the string to a given length, while ensuring that it does not + * chop words. If $substring is provided, and truncating occurs, the string + * is further truncated so that the substring may be appended without + * exceeding the desired length. + * + * @param string $str String to truncate + * @param int $length Desired length of the truncated string + * @param string $substring The substring to append if it can fit + * @param string $encoding The character encoding + * @return string The resulting string after truncating + */ + public static function truncate($str, $length, $substring = '', + $encoding = null) { + $encoding = $encoding ?: mb_internal_encoding(); + + if ($length >= mb_strlen($str, $encoding)) + return $str; + + // Need to further trim the string so we can append the substring + $substringLength = mb_strlen($substring, $encoding); + $length = $length - $substringLength; + + $truncated = mb_substr($str, 0, $length, $encoding); + + // If the last word was truncated + if (mb_strpos($str, ' ', $length - 1, $encoding) != $length) { + // Find pos of the last occurence of a space, and get everything up until + $lastPos = mb_strrpos($truncated, ' ', 0, $encoding); + $truncated = mb_substr($truncated, 0, $lastPos, $encoding); + } + + return $truncated . $substring; + } + } ?> diff --git a/tests/Stringy/StringyTest.php b/tests/Stringy/StringyTest.php index 2f72e76..64efa79 100644 --- a/tests/Stringy/StringyTest.php +++ b/tests/Stringy/StringyTest.php @@ -575,6 +575,43 @@ class StringyTestCase extends PHPUnit_Framework_TestCase { return $testData; } + /** + * @dataProvider stringsForTruncate + */ + public function testTruncate($expected, $string, $length, $substring = '', + $encoding = null) { + $result = S::truncate($string, $length, $substring, $encoding); + $this->assertEquals($expected, $result); + } + + public function stringsForTruncate() { + $testData = array( + array('Test foo bar', 'Test foo bar', 12), + array('Test foo', 'Test foo bar', 11), + array('Test foo', 'Test foo bar', 8), + array('Test', 'Test foo bar', 7), + array('Test', 'Test foo bar', 4), + array('Test foo bar', 'Test foo bar', 12, '...'), + array('Test foo...', 'Test foo bar', 11, '...'), + array('Test...', 'Test foo bar', 8, '...'), + array('Test...', 'Test foo bar', 7, '...'), + array('...', 'Test foo bar', 4, '...'), + array('Test....', 'Test foo bar', 11, '....'), + array('Test fòô bàř', 'Test fòô bàř', 12, '', 'UTF-8'), + array('Test fòô', 'Test fòô bàř', 11, '', 'UTF-8'), + array('Test fòô', 'Test fòô bàř', 8, '', 'UTF-8'), + array('Test', 'Test fòô bàř', 7, '', 'UTF-8'), + array('Test', 'Test fòô bàř', 4, '', 'UTF-8'), + array('Test fòô bàř', 'Test fòô bàř', 12, 'ϰϰ', 'UTF-8'), + array('Test fòôϰϰ', 'Test fòô bàř', 11, 'ϰϰ', 'UTF-8'), + array('Testϰϰ', 'Test fòô bàř', 8, 'ϰϰ', 'UTF-8'), + array('Testϰϰ', 'Test fòô bàř', 7, 'ϰϰ', 'UTF-8'), + array('ϰϰ', 'Test fòô bàř', 4, 'ϰϰ', 'UTF-8') + ); + + return $testData; + } + } ?>