mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-26 14:26:54 +08:00
Fixes #5316: Added startsWith()
and endsWith()
to yii\helpers\StringHelper
. Methods are binary-safe, multibyte-safe and optionally case-insensitive
This commit is contained in:
@ -13,6 +13,7 @@ Yii Framework 2 Change Log
|
|||||||
- Enh #4040: Added `$viewFile` and `$params` to the `EVENT_BEFORE_RENDER` and `EVENT_AFTER_RENDER` events for `View` (qiangxue)
|
- Enh #4040: Added `$viewFile` and `$params` to the `EVENT_BEFORE_RENDER` and `EVENT_AFTER_RENDER` events for `View` (qiangxue)
|
||||||
- Enh #4275: Added `removeChildren()` to `yii\rbac\ManagerInterface` and implementations (samdark)
|
- Enh #4275: Added `removeChildren()` to `yii\rbac\ManagerInterface` and implementations (samdark)
|
||||||
- Enh: Added `yii\base\Application::loadedModules` (qiangxue)
|
- Enh: Added `yii\base\Application::loadedModules` (qiangxue)
|
||||||
|
- Enh #5316: Added `startsWith()` and `endsWith()` to `yii\helpers\StringHelper`. Methods are binary-safe, multibyte-safe and optionally case-insensitive (armab)
|
||||||
- Chg #2037: Dropped the support for using `yii\base\Module` as concrete module classes (qiangxue)
|
- Chg #2037: Dropped the support for using `yii\base\Module` as concrete module classes (qiangxue)
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
namespace yii\helpers;
|
namespace yii\helpers;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BaseStringHelper provides concrete implementation for [[StringHelper]].
|
* BaseStringHelper provides concrete implementation for [[StringHelper]].
|
||||||
*
|
*
|
||||||
@ -100,8 +102,8 @@ class BaseStringHelper
|
|||||||
*/
|
*/
|
||||||
public static function truncate($string, $length, $suffix = '...', $encoding = null)
|
public static function truncate($string, $length, $suffix = '...', $encoding = null)
|
||||||
{
|
{
|
||||||
if (mb_strlen($string, $encoding ?: \Yii::$app->charset) > $length) {
|
if (mb_strlen($string, $encoding ?: Yii::$app->charset) > $length) {
|
||||||
return trim(mb_substr($string, 0, $length, $encoding ?: \Yii::$app->charset)) . $suffix;
|
return trim(mb_substr($string, 0, $length, $encoding ?: Yii::$app->charset)) . $suffix;
|
||||||
} else {
|
} else {
|
||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
@ -124,4 +126,50 @@ class BaseStringHelper
|
|||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if given string starts with specified substring.
|
||||||
|
* Binary and multibyte safe.
|
||||||
|
*
|
||||||
|
* @param string $string Input string
|
||||||
|
* @param string $with Part to search
|
||||||
|
* @param boolean $caseSensitive Case sensitive search. Default is true.
|
||||||
|
* @return boolean Returns true if first input starts with second input, false otherwise
|
||||||
|
*/
|
||||||
|
public static function startsWith($string, $with, $caseSensitive = true)
|
||||||
|
{
|
||||||
|
if (!$bytes = static::byteLength($with)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ($caseSensitive) {
|
||||||
|
return strncmp($string, $with, $bytes) === 0;
|
||||||
|
} else {
|
||||||
|
return mb_strtolower(mb_substr($string, 0, $bytes, '8bit'), Yii::$app->charset) === mb_strtolower($with, Yii::$app->charset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if given string ends with specified substring.
|
||||||
|
* Binary and multibyte safe.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @param string $with
|
||||||
|
* @param boolean $caseSensitive Case sensitive search. Default is true.
|
||||||
|
* @return boolean Returns true if first input ends with second input, false otherwise
|
||||||
|
*/
|
||||||
|
public static function endsWith($string, $with, $caseSensitive = true)
|
||||||
|
{
|
||||||
|
if (!$bytes = static::byteLength($with)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ($caseSensitive) {
|
||||||
|
// Warning check, see http://php.net/manual/en/function.substr-compare.php#refsect1-function.substr-compare-returnvalues
|
||||||
|
if (static::byteLength($string) < $bytes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return substr_compare($string, $with, -$bytes, $bytes) === 0;
|
||||||
|
} else {
|
||||||
|
return mb_strtolower(mb_substr($string, -$bytes, null, '8bit'), Yii::$app->charset) === mb_strtolower($with, Yii::$app->charset);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,4 +114,109 @@ class StringHelperTest extends TestCase
|
|||||||
$this->assertEquals('это тестовая multibyte!!!', StringHelper::truncateWords('это тестовая multibyte строка', 3, '!!!'));
|
$this->assertEquals('это тестовая multibyte!!!', StringHelper::truncateWords('это тестовая multibyte строка', 3, '!!!'));
|
||||||
$this->assertEquals('это строка с неожиданными...', StringHelper::truncateWords('это строка с неожиданными пробелами', 4));
|
$this->assertEquals('это строка с неожиданными...', StringHelper::truncateWords('это строка с неожиданными пробелами', 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerStartsWith
|
||||||
|
*/
|
||||||
|
public function testStartsWith($result, $string, $with)
|
||||||
|
{
|
||||||
|
// case sensitive version check
|
||||||
|
$this->assertSame($result, StringHelper::startsWith($string, $with));
|
||||||
|
// case insensitive version check
|
||||||
|
$this->assertSame($result, StringHelper::startsWith($string, $with, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rules that should work the same for case-sensitive and case-insensitive `startsWith()`
|
||||||
|
*/
|
||||||
|
public function providerStartsWith()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
// positive check
|
||||||
|
[true, '', ''],
|
||||||
|
[true, '', null],
|
||||||
|
[true, 'string', ''],
|
||||||
|
[true, ' string', ' '],
|
||||||
|
[true, 'abc', 'abc'],
|
||||||
|
[true, 'Bürger', 'Bürger'],
|
||||||
|
[true, '我Я multibyte', '我Я'],
|
||||||
|
[true, 'Qנטשופ צרכנות', 'Qנ'],
|
||||||
|
[true, 'ไทย.idn.icann.org', 'ไ'],
|
||||||
|
[true, '!?+', "\x21\x3F"],
|
||||||
|
[true, "\x21?+", '!?'],
|
||||||
|
// false-positive check
|
||||||
|
[false, '', ' '],
|
||||||
|
[false, ' ', ' '],
|
||||||
|
[false, 'Abc', 'Abcde'],
|
||||||
|
[false, 'abc', 'abe'],
|
||||||
|
[false, 'abc', 'b'],
|
||||||
|
[false, 'abc', 'c'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStartsWithCaseSensitive()
|
||||||
|
{
|
||||||
|
$this->assertFalse(StringHelper::startsWith('Abc', 'a'));
|
||||||
|
$this->assertFalse(StringHelper::startsWith('üЯ multibyte', 'Üя multibyte'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStartsWithCaseInsensitive()
|
||||||
|
{
|
||||||
|
$this->assertTrue(StringHelper::startsWith('sTrInG', 'StRiNg', false));
|
||||||
|
$this->assertTrue(StringHelper::startsWith('CaSe', 'cAs', false));
|
||||||
|
$this->assertTrue(StringHelper::startsWith('HTTP://BÜrger.DE/', 'http://bürger.de', false));
|
||||||
|
$this->assertTrue(StringHelper::startsWith('üЯйΨB', 'ÜяЙΨ', false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerEndsWith
|
||||||
|
*/
|
||||||
|
public function testEndsWith($result, $string, $with)
|
||||||
|
{
|
||||||
|
// case sensitive version check
|
||||||
|
$this->assertSame($result, StringHelper::endsWith($string, $with));
|
||||||
|
// case insensitive version check
|
||||||
|
$this->assertSame($result, StringHelper::endsWith($string, $with, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rules that should work the same for case-sensitive and case-insensitive `endsWith()`
|
||||||
|
*/
|
||||||
|
public function providerEndsWith()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
// positive check
|
||||||
|
[true, '', ''],
|
||||||
|
[true, '', null],
|
||||||
|
[true, 'string', ''],
|
||||||
|
[true, 'string ', ' '],
|
||||||
|
[true, 'string', 'g'],
|
||||||
|
[true, 'abc', 'abc'],
|
||||||
|
[true, 'Bürger', 'Bürger'],
|
||||||
|
[true, 'Я multibyte строка我!', ' строка我!'],
|
||||||
|
[true, '+!?', "\x21\x3F"],
|
||||||
|
[true, "+\x21?", "!\x3F"],
|
||||||
|
[true, 'נטשופ צרכנות', 'ת'],
|
||||||
|
// false-positive check
|
||||||
|
[false, '', ' '],
|
||||||
|
[false, ' ', ' '],
|
||||||
|
[false, 'aaa', 'aaaa'],
|
||||||
|
[false, 'abc', 'abe'],
|
||||||
|
[false, 'abc', 'a'],
|
||||||
|
[false, 'abc', 'b'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEndsWithCaseSensitive()
|
||||||
|
{
|
||||||
|
$this->assertFalse(StringHelper::endsWith('string', 'G'));
|
||||||
|
$this->assertFalse(StringHelper::endsWith('multibyte строка', 'А'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEndsWithCaseInsensitive()
|
||||||
|
{
|
||||||
|
$this->assertTrue(StringHelper::endsWith('sTrInG', 'StRiNg', false));
|
||||||
|
$this->assertTrue(StringHelper::endsWith('string', 'nG', false));
|
||||||
|
$this->assertTrue(StringHelper::endsWith('BüЯйΨ', 'ÜяЙΨ', false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user