From bf383b3fe0981dbb564fb598915867f2569e9fdf Mon Sep 17 00:00:00 2001 From: Fan2Shrek Date: Thu, 28 Mar 2024 21:32:04 +0100 Subject: [PATCH 1/2] Mb trim functions --- README.md | 1 + src/Mbstring/Mbstring.php | 58 +++++++++++++++ src/Mbstring/bootstrap.php | 13 ++++ src/Mbstring/bootstrap80.php | 12 ++++ src/Php84/Php84.php | 65 +++++++++++++++++ src/Php84/bootstrap.php | 12 ++++ tests/Mbstring/MbstringTest.php | 123 ++++++++++++++++++++++++++++++++ tests/Php84/Php84Test.php | 123 ++++++++++++++++++++++++++++++++ 8 files changed, 407 insertions(+) diff --git a/README.md b/README.md index 8e1067376..91dd2b5c1 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Polyfills are provided for: - the `mb_ucfirst` and `mb_lcfirst` functions introduced in PHP 8.4; - the `array_find`, `array_find_key`, `array_any` and `array_all` functions introduced in PHP 8.4; - the `Deprecated` attribute introduced in PHP 8.4; +- the `mb_trim`, `mb_ltrim` and `mb_rtrim` functions introduced in PHP 8.4; It is strongly recommended to upgrade your PHP version and/or install the missing extensions whenever possible. This polyfill should be used only when there is no diff --git a/src/Mbstring/Mbstring.php b/src/Mbstring/Mbstring.php index 1ad33a86b..86ee1ed5a 100644 --- a/src/Mbstring/Mbstring.php +++ b/src/Mbstring/Mbstring.php @@ -50,6 +50,9 @@ * - mb_substr_count - Count the number of substring occurrences * - mb_ucfirst - Make a string's first character uppercase * - mb_lcfirst - Make a string's first character lowercase + * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string + * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string + * - mb_rtrim - Strip whitespace (or other characters) from the end of a string * * Not implemented: * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) @@ -76,6 +79,8 @@ final class Mbstring ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], ]; + private const CHARACTERS = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; + private static $encodingList = ['ASCII', 'UTF-8']; private static $language = 'neutral'; private static $internalEncoding = 'UTF-8'; @@ -980,6 +985,59 @@ private static function getEncoding($encoding) return $encoding; } + public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('^[%s]+|[%s]+$', $string, $characters, $encoding); + } + + public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('^[%s]+', $string, $characters, $encoding); + } + + public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('[%s]+$', $string, $characters, $encoding); + } + + private static function mb_internal_trim(string $regex, string $string, ?string $characters = null, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = mb_internal_encoding(); + } + + self::assertEncoding($encoding, debug_backtrace()[1]['function'].'(): Argument #3 ($encoding) must be a valid encoding, "%s" given.'); + + if ('' === $characters) { + return null === $encoding ? $string : mb_convert_encoding($string, $encoding); + } + + if (null === $characters) { + $characters = self::CHARACTERS; + } + + $regexCharacter = preg_quote($characters ?? '', '/'); + $regex = sprintf($regex, $regexCharacter, $regexCharacter); + + if ('ASCII' === mb_detect_encoding($characters) && 'ASCII' === mb_detect_encoding($string) && !empty(array_intersect(str_split(self::CHARACTERS), str_split($string)))) { + $options = 'g'; + } else { + $options = ''; + } + + try { + $test = mb_ereg_replace($regex, "", $string, $options); + + if (null === $test) { + throw new \Exception(); + } + + return $test; + } catch (\Exception $e) { + return preg_replace('/'.$regex.'/', "", $string); + } + } + private static function assertEncoding(string $encoding, string $errorFormat): void { try { diff --git a/src/Mbstring/bootstrap.php b/src/Mbstring/bootstrap.php index 6e4b5fce8..ff51ae079 100644 --- a/src/Mbstring/bootstrap.php +++ b/src/Mbstring/bootstrap.php @@ -144,6 +144,19 @@ function mb_ucfirst(string $string, ?string $encoding = null): string { return p function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } } +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + + if (extension_loaded('mbstring')) { return; } diff --git a/src/Mbstring/bootstrap80.php b/src/Mbstring/bootstrap80.php index ec2ae4276..8016bdb48 100644 --- a/src/Mbstring/bootstrap80.php +++ b/src/Mbstring/bootstrap80.php @@ -140,6 +140,18 @@ function mb_ucfirst($string, ?string $encoding = null): string { return p\Mbstri function mb_lcfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } } +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + if (extension_loaded('mbstring')) { return; } diff --git a/src/Php84/Php84.php b/src/Php84/Php84.php index 992675574..3a7a3a751 100644 --- a/src/Php84/Php84.php +++ b/src/Php84/Php84.php @@ -13,11 +13,14 @@ /** * @author Ayesh Karunaratne + * @author Pierre Ambroise * * @internal */ final class Php84 { + private const CHARACTERS = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; + public static function mb_ucfirst(string $string, ?string $encoding = null): string { if (null === $encoding) { @@ -107,4 +110,66 @@ public static function array_all(array $array, callable $callback): bool return true; } + + public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('^[%s]+|[%s]+$', $string, $characters, $encoding); + } + + public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('^[%s]+', $string, $characters, $encoding); + } + + public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('[%s]+$', $string, $characters, $encoding); + } + + private static function mb_internal_trim(string $regex, string $string, ?string $characters = null, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = mb_internal_encoding(); + } + + try { + $validEncoding = @mb_check_encoding('', $encoding); + } catch (\ValueError $e) { + throw new \ValueError(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given.', debug_backtrace()[1]['function'], $encoding)); + } + + // BC for PHP 7.3 and lower + if (!$validEncoding) { + throw new \ValueError(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given.', debug_backtrace()[1]['function'], $encoding)); + } + + if ('' === $characters) { + return null === $encoding ? $string : mb_convert_encoding($string, $encoding); + } + + if (null === $characters) { + $characters = self::CHARACTERS; + } + + $regexCharacter = preg_quote($characters ?? '', '/'); + $regex = sprintf($regex, $regexCharacter, $regexCharacter); + + if ('ASCII' === mb_detect_encoding($characters) && 'ASCII' === mb_detect_encoding($string) && !empty(array_intersect(str_split(self::CHARACTERS), str_split($string)))) { + $options = 'g'; + } else { + $options = ''; + } + + try { + $test = mb_ereg_replace($regex, "", $string, $options); + + if (null === $test) { + throw new \Exception(); + } + + return $test; + } catch (\Exception $e) { + return preg_replace(sprintf('/%s/', $regex), "", $string); + } + } } diff --git a/src/Php84/bootstrap.php b/src/Php84/bootstrap.php index fc337c50d..8f8e2340b 100644 --- a/src/Php84/bootstrap.php +++ b/src/Php84/bootstrap.php @@ -38,3 +38,15 @@ function array_any(array $array, callable $callback): bool { return p\Php84::arr if (!function_exists('array_all')) { function array_all(array $array, callable $callback): bool { return p\Php84::array_all($array, $callback); } } + +if (!function_exists('mb_trim') && extension_loaded('mbstring')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim') && extension_loaded('mbstring')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim') && extension_loaded('mbstring')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_rtrim($string, $characters, $encoding); } +} diff --git a/tests/Mbstring/MbstringTest.php b/tests/Mbstring/MbstringTest.php index 8aa26d578..5332410c4 100644 --- a/tests/Mbstring/MbstringTest.php +++ b/tests/Mbstring/MbstringTest.php @@ -808,4 +808,127 @@ public static function lcFirstDataProvider(): array ['ß', 'ß'], ]; } + + /** + * @covers \Symfony\Polyfill\Php84\Php84::mb_trim + * + * @dataProvider mbTrimProvider + */ + public function testMbTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void + { + $this->assertSame($expected, mb_trim($string, $characters, $encoding)); + } + + /** + * @covers \Symfony\Polyfill\Php84\Php84::mb_ltrim + * + * @dataProvider mbLTrimProvider + */ + public function testMbLTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void + { + $this->assertSame($expected, mb_ltrim($string, $characters, $encoding)); + } + + /** + * @covers \Symfony\Polyfill\Php84\Php84::mb_rtrim + * + * @dataProvider mbRTrimProvider + */ + public function testMbRTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void + { + $this->assertSame($expected, mb_rtrim($string, $characters, $encoding)); + } + + public function testMbTrimException(): void + { + $this->expectException(\ValueError::class); + mb_trim("\u{180F}", "", "NULL"); + } + + public function testMbTrimEncoding(): void + { + $this->assertSame('あ', mb_convert_encoding(mb_trim("\x81\x40\x82\xa0\x81\x40", "\x81\x40", "SJIS"), "UTF-8", "SJIS")); + $this->assertSame('226f575b', bin2hex(mb_ltrim(mb_convert_encoding("\u{FFFE}漢字", "UTF-16LE", "UTF-8"), mb_convert_encoding("\u{FFFE}\u{FEFF}", "UTF-16LE", "UTF-8"), "UTF-16LE"))); + $this->assertSame('6f225b57', bin2hex(mb_ltrim(mb_convert_encoding("\u{FEFF}漢字", "UTF-16BE", "UTF-8"), mb_convert_encoding("\u{FFFE}\u{FEFF}", "UTF-16BE", "UTF-8"), "UTF-16BE"))); + } + + public function testMbTrimCharactersEncoding(): void + { + $strUtf8 = "\u{3042}\u{3000}"; + + $this->assertSame(1, mb_strlen(mb_trim($strUtf8))); + $this->assertSame(1, mb_strlen(mb_trim($strUtf8, null, 'UTF-8'))); + + $old = mb_internal_encoding(); + mb_internal_encoding('Shift_JIS'); + $strSjis = mb_convert_encoding($strUtf8, 'Shift_JIS', 'UTF-8'); + + $this->assertSame(1, mb_strlen(mb_trim($strSjis))); + $this->assertSame(1, mb_strlen(mb_trim($strSjis, null, 'Shift_JIS'))); + mb_internal_encoding($old); + } + + public static function mbTrimProvider(): iterable + { + yield ['ABC', 'ABC']; + yield ['ABC', "\0\t\nABC \0\t\n"]; + yield ["\0\t\nABC \0\t\n", "\0\t\nABC \0\t\n", '']; + + yield ['', '']; + + yield ["あいうえおあお", " あいうえおあお ", " ", "UTF-8"]; + yield ["foo BAR Spa", "foo BAR Spaß", "ß", "UTF-8"]; + yield ["oo BAR Spaß", "oo BAR Spaß", "f", "UTF-8"]; + + yield ["oo BAR Spa", "foo BAR Spaß", "ßf", "UTF-8"]; + yield ["oo BAR Spa", "foo BAR Spaß", "fß", "UTF-8"]; + yield ["いうおえお", " あいうおえお あ", " あ", "UTF-8"]; + yield ["いうおえお", " あいうおえお あ", "あ ", "UTF-8"]; + yield [" あいうおえお ", " あいうおえお a", "あa", "UTF-8"]; + yield [" あいうおえお a", " あいうおえお a", "\xe3", "UTF-8"]; + + yield ["", str_repeat(" ", 129)]; + yield ["a", str_repeat(" ", 129) . "a"]; + + yield ["", " \f\n\r\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"]; + + yield [' abcd ', ' abcd ', '']; + + yield ['f', 'foo', 'oo']; + + yield ["foo\n", "foo\n", 'o']; + } + + public static function mbLTrimProvider(): iterable + { + yield ['ABC', 'ABC']; + yield ["ABC \0\t\n", "\0\t\nABC \0\t\n"]; + yield ["\0\t\nABC \0\t\n", "\0\t\nABC \0\t\n", '']; + + yield ['', '']; + + yield [' test ', ' test ', '']; + + yield ['いああああ', 'あああああああああああああああああああああああああああああああああいああああ', 'あ']; + + yield ["漢字", "\u{FFFE}漢字", "\u{FFFE}\u{FEFF}"]; + yield [' abcd ', ' abcd ', '']; + } + + public static function mbRTrimProvider(): iterable + { + yield ['ABC', 'ABC']; + yield ["ABC", "ABC \0\t\n"]; + yield ["\0\t\nABC \0\t\n", "\0\t\nABC \0\t\n", '']; + + yield ['', '']; + + yield [" a", str_repeat(" ", 129) . "a"]; + + yield ['あああああああああああああああああああああああああああああああああい', 'あああああああああああああああああああああああああああああああああいああああ', 'あ']; + + yield [' abcd ', ' abcd ', '']; + + yield ["foo\n", "foo\n", 'o']; + } } diff --git a/tests/Php84/Php84Test.php b/tests/Php84/Php84Test.php index 73d919452..1eb6aaace 100644 --- a/tests/Php84/Php84Test.php +++ b/tests/Php84/Php84Test.php @@ -182,4 +182,127 @@ public static function arrayAllDataProvider(): array [[1 => '1', 2 => '12', 3 => '123', 4 => '1234'], $callableKey, true], ]; } + + /** + * @covers \Symfony\Polyfill\Php84\Php84::mb_trim + * + * @dataProvider mbTrimProvider + */ + public function testMbTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void + { + $this->assertSame($expected, mb_trim($string, $characters, $encoding)); + } + + /** + * @covers \Symfony\Polyfill\Php84\Php84::mb_ltrim + * + * @dataProvider mbLTrimProvider + */ + public function testMbLTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void + { + $this->assertSame($expected, mb_ltrim($string, $characters, $encoding)); + } + + /** + * @covers \Symfony\Polyfill\Php84\Php84::mb_rtrim + * + * @dataProvider mbRTrimProvider + */ + public function testMbRTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void + { + $this->assertSame($expected, mb_rtrim($string, $characters, $encoding)); + } + + public function testMbTrimException(): void + { + $this->expectException(\ValueError::class); + mb_trim("\u{180F}", "", "NULL"); + } + + public function testMbTrimEncoding(): void + { + $this->assertSame('あ', mb_convert_encoding(mb_trim("\x81\x40\x82\xa0\x81\x40", "\x81\x40", "SJIS"), "UTF-8", "SJIS")); + $this->assertSame('226f575b', bin2hex(mb_ltrim(mb_convert_encoding("\u{FFFE}漢字", "UTF-16LE", "UTF-8"), mb_convert_encoding("\u{FFFE}\u{FEFF}", "UTF-16LE", "UTF-8"), "UTF-16LE"))); + $this->assertSame('6f225b57', bin2hex(mb_ltrim(mb_convert_encoding("\u{FEFF}漢字", "UTF-16BE", "UTF-8"), mb_convert_encoding("\u{FFFE}\u{FEFF}", "UTF-16BE", "UTF-8"), "UTF-16BE"))); + } + + public function testMbTrimCharactersEncoding(): void + { + $strUtf8 = "\u{3042}\u{3000}"; + + $this->assertSame(1, mb_strlen(mb_trim($strUtf8))); + $this->assertSame(1, mb_strlen(mb_trim($strUtf8, null, 'UTF-8'))); + + $old = mb_internal_encoding(); + mb_internal_encoding('Shift_JIS'); + $strSjis = mb_convert_encoding($strUtf8, 'Shift_JIS', 'UTF-8'); + + $this->assertSame(1, mb_strlen(mb_trim($strSjis))); + $this->assertSame(1, mb_strlen(mb_trim($strSjis, null, 'Shift_JIS'))); + mb_internal_encoding($old); + } + + public static function mbTrimProvider(): iterable + { + yield ['ABC', 'ABC']; + yield ['ABC', "\0\t\nABC \0\t\n"]; + yield ["\0\t\nABC \0\t\n", "\0\t\nABC \0\t\n", '']; + + yield ['', '']; + + yield ["あいうえおあお", " あいうえおあお ", " ", "UTF-8"]; + yield ["foo BAR Spa", "foo BAR Spaß", "ß", "UTF-8"]; + yield ["oo BAR Spaß", "oo BAR Spaß", "f", "UTF-8"]; + + yield ["oo BAR Spa", "foo BAR Spaß", "ßf", "UTF-8"]; + yield ["oo BAR Spa", "foo BAR Spaß", "fß", "UTF-8"]; + yield ["いうおえお", " あいうおえお あ", " あ", "UTF-8"]; + yield ["いうおえお", " あいうおえお あ", "あ ", "UTF-8"]; + yield [" あいうおえお ", " あいうおえお a", "あa", "UTF-8"]; + yield [" あいうおえお a", " あいうおえお a", "\xe3", "UTF-8"]; + + yield ["", str_repeat(" ", 129)]; + yield ["a", str_repeat(" ", 129) . "a"]; + + yield ["", " \f\n\r\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"]; + + yield [' abcd ', ' abcd ', '']; + + yield ['f', 'foo', 'oo']; + + yield ["foo\n", "foo\n", 'o']; + } + + public static function mbLTrimProvider(): iterable + { + yield ['ABC', 'ABC']; + yield ["ABC \0\t\n", "\0\t\nABC \0\t\n"]; + yield ["\0\t\nABC \0\t\n", "\0\t\nABC \0\t\n", '']; + + yield ['', '']; + + yield [' test ', ' test ', '']; + + yield ['いああああ', 'あああああああああああああああああああああああああああああああああいああああ', 'あ']; + + yield ["漢字", "\u{FFFE}漢字", "\u{FFFE}\u{FEFF}"]; + yield [' abcd ', ' abcd ', '']; + } + + public static function mbRTrimProvider(): iterable + { + yield ['ABC', 'ABC']; + yield ["ABC", "ABC \0\t\n"]; + yield ["\0\t\nABC \0\t\n", "\0\t\nABC \0\t\n", '']; + + yield ['', '']; + + yield [" a", str_repeat(" ", 129) . "a"]; + + yield ['あああああああああああああああああああああああああああああああああい', 'あああああああああああああああああああああああああああああああああいああああ', 'あ']; + + yield [' abcd ', ' abcd ', '']; + + yield ["foo\n", "foo\n", 'o']; + } } From dd8aab5c66f11585b4fb8c122743fa79f2a09e6b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 20 Jun 2024 09:42:09 +0200 Subject: [PATCH 2/2] Improve mb_*trim polyfills --- src/Mbstring/Mbstring.php | 65 +++++++++++++----------- src/Php72/bootstrap.php | 19 ++++--- src/Php74/bootstrap.php | 8 +-- src/Php83/bootstrap.php | 6 ++- src/Php84/Php84.php | 47 ++++++++--------- src/Php84/Resources/stubs/Deprecated.php | 2 +- src/Php84/bootstrap.php | 34 +++++++------ tests/Mbstring/MbstringTest.php | 44 ++++++++-------- tests/Php84/Php84Test.php | 46 ++++++++--------- 9 files changed, 140 insertions(+), 131 deletions(-) diff --git a/src/Mbstring/Mbstring.php b/src/Mbstring/Mbstring.php index 86ee1ed5a..7be551bb8 100644 --- a/src/Mbstring/Mbstring.php +++ b/src/Mbstring/Mbstring.php @@ -79,8 +79,6 @@ final class Mbstring ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], ]; - private const CHARACTERS = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; - private static $encodingList = ['ASCII', 'UTF-8']; private static $language = 'neutral'; private static $internalEncoding = 'UTF-8'; @@ -88,7 +86,7 @@ final class Mbstring public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) { if (\is_array($s)) { - if (PHP_VERSION_ID < 70200) { + if (\PHP_VERSION_ID < 70200) { trigger_error('mb_convert_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING); return null; @@ -987,68 +985,73 @@ private static function getEncoding($encoding) public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('^[%s]+|[%s]+$', $string, $characters, $encoding); + return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__); } public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('^[%s]+', $string, $characters, $encoding); + return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__); } public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('[%s]+$', $string, $characters, $encoding); + return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__); } - private static function mb_internal_trim(string $regex, string $string, ?string $characters = null, ?string $encoding = null): string + private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string { if (null === $encoding) { - $encoding = mb_internal_encoding(); + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given'); } - self::assertEncoding($encoding, debug_backtrace()[1]['function'].'(): Argument #3 ($encoding) must be a valid encoding, "%s" given.'); - if ('' === $characters) { - return null === $encoding ? $string : mb_convert_encoding($string, $encoding); + return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding); } - if (null === $characters) { - $characters = self::CHARACTERS; - } + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $string)) { + $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string); + } + if (null !== $characters && !preg_match('//u', $characters)) { + $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters); + } + } else { + $string = iconv($encoding, 'UTF-8//IGNORE', $string); - $regexCharacter = preg_quote($characters ?? '', '/'); - $regex = sprintf($regex, $regexCharacter, $regexCharacter); + if (null !== $characters) { + $characters = iconv($encoding, 'UTF-8//IGNORE', $characters); + } + } - if ('ASCII' === mb_detect_encoding($characters) && 'ASCII' === mb_detect_encoding($string) && !empty(array_intersect(str_split(self::CHARACTERS), str_split($string)))) { - $options = 'g'; + if (null === $characters) { + $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; } else { - $options = ''; + $characters = preg_quote($characters); } - - try { - $test = mb_ereg_replace($regex, "", $string, $options); - if (null === $test) { - throw new \Exception(); - } + $string = preg_replace(sprintf($regex, $characters), '', $string); - return $test; - } catch (\Exception $e) { - return preg_replace('/'.$regex.'/', "", $string); + if (null === $encoding) { + return $string; } - } + + return iconv('UTF-8', $encoding.'//IGNORE', $string); + } private static function assertEncoding(string $encoding, string $errorFormat): void { try { $validEncoding = @self::mb_check_encoding('', $encoding); } catch (\ValueError $e) { - throw new \ValueError(\sprintf($errorFormat, $encoding)); + throw new \ValueError(sprintf($errorFormat, $encoding)); } // BC for PHP 7.3 and lower if (!$validEncoding) { - throw new \ValueError(\sprintf($errorFormat, $encoding)); + throw new \ValueError(sprintf($errorFormat, $encoding)); } } } diff --git a/src/Php72/bootstrap.php b/src/Php72/bootstrap.php index b5c92d4c7..00d793c41 100644 --- a/src/Php72/bootstrap.php +++ b/src/Php72/bootstrap.php @@ -46,12 +46,15 @@ function utf8_decode($string) { return p\Php72::utf8_decode($string); } if (!function_exists('spl_object_id')) { function spl_object_id($object) { return p\Php72::spl_object_id($object); } } -if (!function_exists('mb_ord')) { - function mb_ord($string, $encoding = null) { return p\Php72::mb_ord($string, $encoding); } -} -if (!function_exists('mb_chr')) { - function mb_chr($codepoint, $encoding = null) { return p\Php72::mb_chr($codepoint, $encoding); } -} -if (!function_exists('mb_scrub')) { - function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } + +if (extension_loaded('mbstring')) { + if (!function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) { return p\Php72::mb_ord($string, $encoding); } + } + if (!function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) { return p\Php72::mb_chr($codepoint, $encoding); } + } + if (!function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } + } } diff --git a/src/Php74/bootstrap.php b/src/Php74/bootstrap.php index f6a11f157..c894d99f3 100644 --- a/src/Php74/bootstrap.php +++ b/src/Php74/bootstrap.php @@ -18,9 +18,11 @@ if (!function_exists('get_mangled_object_vars')) { function get_mangled_object_vars($object) { return p\Php74::get_mangled_object_vars($object); } } -if (!function_exists('mb_str_split') && function_exists('mb_substr')) { - function mb_str_split($string, $length = 1, $encoding = null) { return p\Php74::mb_str_split($string, $length, $encoding); } -} if (!function_exists('password_algos')) { function password_algos() { return p\Php74::password_algos(); } } +if (extension_loaded('mbstring')) { + if (!function_exists('mb_str_split')) { + function mb_str_split($string, $length = 1, $encoding = null) { return p\Php74::mb_str_split($string, $length, $encoding); } + } +} diff --git a/src/Php83/bootstrap.php b/src/Php83/bootstrap.php index f43af17e0..a92799cb3 100644 --- a/src/Php83/bootstrap.php +++ b/src/Php83/bootstrap.php @@ -19,8 +19,10 @@ function json_validate(string $json, int $depth = 512, int $flags = 0): bool { return p\Php83::json_validate($json, $depth, $flags); } } -if (!function_exists('mb_str_pad') && function_exists('mb_substr')) { - function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +if (extension_loaded('mbstring')) { + if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } + } } if (!function_exists('stream_context_set_options')) { diff --git a/src/Php84/Php84.php b/src/Php84/Php84.php index 3a7a3a751..1bca70b56 100644 --- a/src/Php84/Php84.php +++ b/src/Php84/Php84.php @@ -19,8 +19,6 @@ */ final class Php84 { - private const CHARACTERS = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; - public static function mb_ucfirst(string $string, ?string $encoding = null): string { if (null === $encoding) { @@ -113,20 +111,20 @@ public static function array_all(array $array, callable $callback): bool public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('^[%s]+|[%s]+$', $string, $characters, $encoding); + return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__); } public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('^[%s]+', $string, $characters, $encoding); + return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__); } public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('[%s]+$', $string, $characters, $encoding); + return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__); } - private static function mb_internal_trim(string $regex, string $string, ?string $characters = null, ?string $encoding = null): string + private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string { if (null === $encoding) { $encoding = mb_internal_encoding(); @@ -135,41 +133,40 @@ private static function mb_internal_trim(string $regex, string $string, ?string try { $validEncoding = @mb_check_encoding('', $encoding); } catch (\ValueError $e) { - throw new \ValueError(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given.', debug_backtrace()[1]['function'], $encoding)); + throw new \ValueError(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given', $function, $encoding)); } // BC for PHP 7.3 and lower if (!$validEncoding) { - throw new \ValueError(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given.', debug_backtrace()[1]['function'], $encoding)); + throw new \ValueError(sprintf('%s(): Argument #3 ($encoding) must be a valid encoding, "%s" given', $function, $encoding)); } if ('' === $characters) { return null === $encoding ? $string : mb_convert_encoding($string, $encoding); } - if (null === $characters) { - $characters = self::CHARACTERS; + if ('UTF-8' === $encoding || \in_array(strtolower($encoding), ['utf-8', 'utf8'], true)) { + $encoding = 'UTF-8'; } - $regexCharacter = preg_quote($characters ?? '', '/'); - $regex = sprintf($regex, $regexCharacter, $regexCharacter); + $string = mb_convert_encoding($string, 'UTF-8', $encoding); - if ('ASCII' === mb_detect_encoding($characters) && 'ASCII' === mb_detect_encoding($string) && !empty(array_intersect(str_split(self::CHARACTERS), str_split($string)))) { - $options = 'g'; + if (null !== $characters) { + $characters = mb_convert_encoding($characters, 'UTF-8', $encoding); + } + + if (null === $characters) { + $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; } else { - $options = ''; + $characters = preg_quote($characters); } - - try { - $test = mb_ereg_replace($regex, "", $string, $options); - if (null === $test) { - throw new \Exception(); - } + $string = preg_replace(sprintf($regex, $characters), '', $string); - return $test; - } catch (\Exception $e) { - return preg_replace(sprintf('/%s/', $regex), "", $string); + if ('UTF-8' === $encoding) { + return $string; } - } + + return mb_convert_encoding($string, $encoding, 'UTF-8'); + } } diff --git a/src/Php84/Resources/stubs/Deprecated.php b/src/Php84/Resources/stubs/Deprecated.php index aa039e3e5..f3e6a4f8e 100644 --- a/src/Php84/Resources/stubs/Deprecated.php +++ b/src/Php84/Resources/stubs/Deprecated.php @@ -15,7 +15,7 @@ final class Deprecated { public readonly ?string $message; public readonly ?string $since; - + public function __construct(?string $message = null, ?string $since = null) { $this->message = $message; diff --git a/src/Php84/bootstrap.php b/src/Php84/bootstrap.php index 8f8e2340b..5a86f206f 100644 --- a/src/Php84/bootstrap.php +++ b/src/Php84/bootstrap.php @@ -15,14 +15,6 @@ return; } -if (!function_exists('mb_ucfirst')) { - function mb_ucfirst($string, ?string $encoding = null): string { return p\Php84::mb_ucfirst($string, $encoding); } -} - -if (!function_exists('mb_lcfirst')) { - function mb_lcfirst($string, ?string $encoding = null): string { return p\Php84::mb_lcfirst($string, $encoding); } -} - if (!function_exists('array_find')) { function array_find(array $array, callable $callback) { return p\Php84::array_find($array, $callback); } } @@ -39,14 +31,24 @@ function array_any(array $array, callable $callback): bool { return p\Php84::arr function array_all(array $array, callable $callback): bool { return p\Php84::array_all($array, $callback); } } -if (!function_exists('mb_trim') && extension_loaded('mbstring')) { - function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_trim($string, $characters, $encoding); } -} +if (extension_loaded('mbstring')) { + if (!function_exists('mb_ucfirst')) { + function mb_ucfirst($string, ?string $encoding = null): string { return p\Php84::mb_ucfirst($string, $encoding); } + } -if (!function_exists('mb_ltrim') && extension_loaded('mbstring')) { - function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_ltrim($string, $characters, $encoding); } -} + if (!function_exists('mb_lcfirst')) { + function mb_lcfirst($string, ?string $encoding = null): string { return p\Php84::mb_lcfirst($string, $encoding); } + } + + if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_trim($string, $characters, $encoding); } + } + + if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_ltrim($string, $characters, $encoding); } + } -if (!function_exists('mb_rtrim') && extension_loaded('mbstring')) { - function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_rtrim($string, $characters, $encoding); } + if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Php84::mb_rtrim($string, $characters, $encoding); } + } } diff --git a/tests/Mbstring/MbstringTest.php b/tests/Mbstring/MbstringTest.php index 5332410c4..aea3f4caf 100644 --- a/tests/Mbstring/MbstringTest.php +++ b/tests/Mbstring/MbstringTest.php @@ -811,7 +811,7 @@ public static function lcFirstDataProvider(): array /** * @covers \Symfony\Polyfill\Php84\Php84::mb_trim - * + * * @dataProvider mbTrimProvider */ public function testMbTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void @@ -821,7 +821,7 @@ public function testMbTrim(string $expected, string $string, ?string $characters /** * @covers \Symfony\Polyfill\Php84\Php84::mb_ltrim - * + * * @dataProvider mbLTrimProvider */ public function testMbLTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void @@ -831,7 +831,7 @@ public function testMbLTrim(string $expected, string $string, ?string $character /** * @covers \Symfony\Polyfill\Php84\Php84::mb_rtrim - * + * * @dataProvider mbRTrimProvider */ public function testMbRTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void @@ -842,14 +842,14 @@ public function testMbRTrim(string $expected, string $string, ?string $character public function testMbTrimException(): void { $this->expectException(\ValueError::class); - mb_trim("\u{180F}", "", "NULL"); + mb_trim("\u{180F}", '', 'NULL'); } public function testMbTrimEncoding(): void { - $this->assertSame('あ', mb_convert_encoding(mb_trim("\x81\x40\x82\xa0\x81\x40", "\x81\x40", "SJIS"), "UTF-8", "SJIS")); - $this->assertSame('226f575b', bin2hex(mb_ltrim(mb_convert_encoding("\u{FFFE}漢字", "UTF-16LE", "UTF-8"), mb_convert_encoding("\u{FFFE}\u{FEFF}", "UTF-16LE", "UTF-8"), "UTF-16LE"))); - $this->assertSame('6f225b57', bin2hex(mb_ltrim(mb_convert_encoding("\u{FEFF}漢字", "UTF-16BE", "UTF-8"), mb_convert_encoding("\u{FFFE}\u{FEFF}", "UTF-16BE", "UTF-8"), "UTF-16BE"))); + $this->assertSame('あ', mb_convert_encoding(mb_trim("\x81\x40\x82\xa0\x81\x40", "\x81\x40", 'SJIS'), 'UTF-8', 'SJIS')); + $this->assertSame('226f575b', bin2hex(mb_ltrim(mb_convert_encoding("\u{FFFE}漢字", 'UTF-16LE', 'UTF-8'), mb_convert_encoding("\u{FFFE}\u{FEFF}", 'UTF-16LE', 'UTF-8'), 'UTF-16LE'))); + $this->assertSame('6f225b57', bin2hex(mb_ltrim(mb_convert_encoding("\u{FEFF}漢字", 'UTF-16BE', 'UTF-8'), mb_convert_encoding("\u{FFFE}\u{FEFF}", 'UTF-16BE', 'UTF-8'), 'UTF-16BE'))); } public function testMbTrimCharactersEncoding(): void @@ -876,21 +876,21 @@ public static function mbTrimProvider(): iterable yield ['', '']; - yield ["あいうえおあお", " あいうえおあお ", " ", "UTF-8"]; - yield ["foo BAR Spa", "foo BAR Spaß", "ß", "UTF-8"]; - yield ["oo BAR Spaß", "oo BAR Spaß", "f", "UTF-8"]; + yield ['あいうえおあお', ' あいうえおあお ', ' ', 'UTF-8']; + yield ['foo BAR Spa', 'foo BAR Spaß', 'ß', 'UTF-8']; + yield ['oo BAR Spaß', 'oo BAR Spaß', 'f', 'UTF-8']; - yield ["oo BAR Spa", "foo BAR Spaß", "ßf", "UTF-8"]; - yield ["oo BAR Spa", "foo BAR Spaß", "fß", "UTF-8"]; - yield ["いうおえお", " あいうおえお あ", " あ", "UTF-8"]; - yield ["いうおえお", " あいうおえお あ", "あ ", "UTF-8"]; - yield [" あいうおえお ", " あいうおえお a", "あa", "UTF-8"]; - yield [" あいうおえお a", " あいうおえお a", "\xe3", "UTF-8"]; + yield ['oo BAR Spa', 'foo BAR Spaß', 'ßf', 'UTF-8']; + yield ['oo BAR Spa', 'foo BAR Spaß', 'fß', 'UTF-8']; + yield ['いうおえお', ' あいうおえお あ', ' あ', 'UTF-8']; + yield ['いうおえお', ' あいうおえお あ', 'あ ', 'UTF-8']; + yield [' あいうおえお ', ' あいうおえお a', 'あa', 'UTF-8']; + yield [' あいうおえお a', ' あいうおえお a', "\xe3", 'UTF-8']; - yield ["", str_repeat(" ", 129)]; - yield ["a", str_repeat(" ", 129) . "a"]; + yield ['', str_repeat(' ', 129)]; + yield ['a', str_repeat(' ', 129).'a']; - yield ["", " \f\n\r\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"]; + yield ['', " \f\n\r\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"]; yield [' abcd ', ' abcd ', '']; @@ -911,19 +911,19 @@ public static function mbLTrimProvider(): iterable yield ['いああああ', 'あああああああああああああああああああああああああああああああああいああああ', 'あ']; - yield ["漢字", "\u{FFFE}漢字", "\u{FFFE}\u{FEFF}"]; + yield ['漢字', "\u{FFFE}漢字", "\u{FFFE}\u{FEFF}"]; yield [' abcd ', ' abcd ', '']; } public static function mbRTrimProvider(): iterable { yield ['ABC', 'ABC']; - yield ["ABC", "ABC \0\t\n"]; + yield ['ABC', "ABC \0\t\n"]; yield ["\0\t\nABC \0\t\n", "\0\t\nABC \0\t\n", '']; yield ['', '']; - yield [" a", str_repeat(" ", 129) . "a"]; + yield [' a', str_repeat(' ', 129).'a']; yield ['あああああああああああああああああああああああああああああああああい', 'あああああああああああああああああああああああああああああああああいああああ', 'あ']; diff --git a/tests/Php84/Php84Test.php b/tests/Php84/Php84Test.php index 1eb6aaace..0989113a0 100644 --- a/tests/Php84/Php84Test.php +++ b/tests/Php84/Php84Test.php @@ -182,10 +182,10 @@ public static function arrayAllDataProvider(): array [[1 => '1', 2 => '12', 3 => '123', 4 => '1234'], $callableKey, true], ]; } - + /** * @covers \Symfony\Polyfill\Php84\Php84::mb_trim - * + * * @dataProvider mbTrimProvider */ public function testMbTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void @@ -195,7 +195,7 @@ public function testMbTrim(string $expected, string $string, ?string $characters /** * @covers \Symfony\Polyfill\Php84\Php84::mb_ltrim - * + * * @dataProvider mbLTrimProvider */ public function testMbLTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void @@ -205,7 +205,7 @@ public function testMbLTrim(string $expected, string $string, ?string $character /** * @covers \Symfony\Polyfill\Php84\Php84::mb_rtrim - * + * * @dataProvider mbRTrimProvider */ public function testMbRTrim(string $expected, string $string, ?string $characters = null, ?string $encoding = null): void @@ -216,14 +216,14 @@ public function testMbRTrim(string $expected, string $string, ?string $character public function testMbTrimException(): void { $this->expectException(\ValueError::class); - mb_trim("\u{180F}", "", "NULL"); + mb_trim("\u{180F}", '', 'NULL'); } public function testMbTrimEncoding(): void { - $this->assertSame('あ', mb_convert_encoding(mb_trim("\x81\x40\x82\xa0\x81\x40", "\x81\x40", "SJIS"), "UTF-8", "SJIS")); - $this->assertSame('226f575b', bin2hex(mb_ltrim(mb_convert_encoding("\u{FFFE}漢字", "UTF-16LE", "UTF-8"), mb_convert_encoding("\u{FFFE}\u{FEFF}", "UTF-16LE", "UTF-8"), "UTF-16LE"))); - $this->assertSame('6f225b57', bin2hex(mb_ltrim(mb_convert_encoding("\u{FEFF}漢字", "UTF-16BE", "UTF-8"), mb_convert_encoding("\u{FFFE}\u{FEFF}", "UTF-16BE", "UTF-8"), "UTF-16BE"))); + $this->assertSame('あ', mb_convert_encoding(mb_trim("\x81\x40\x82\xa0\x81\x40", "\x81\x40", 'SJIS'), 'UTF-8', 'SJIS')); + $this->assertSame('226f575b', bin2hex(mb_ltrim(mb_convert_encoding("\u{FFFE}漢字", 'UTF-16LE', 'UTF-8'), mb_convert_encoding("\u{FFFE}\u{FEFF}", 'UTF-16LE', 'UTF-8'), 'UTF-16LE'))); + $this->assertSame('6f225b57', bin2hex(mb_ltrim(mb_convert_encoding("\u{FEFF}漢字", 'UTF-16BE', 'UTF-8'), mb_convert_encoding("\u{FFFE}\u{FEFF}", 'UTF-16BE', 'UTF-8'), 'UTF-16BE'))); } public function testMbTrimCharactersEncoding(): void @@ -250,21 +250,21 @@ public static function mbTrimProvider(): iterable yield ['', '']; - yield ["あいうえおあお", " あいうえおあお ", " ", "UTF-8"]; - yield ["foo BAR Spa", "foo BAR Spaß", "ß", "UTF-8"]; - yield ["oo BAR Spaß", "oo BAR Spaß", "f", "UTF-8"]; + yield ['あいうえおあお', ' あいうえおあお ', ' ', 'UTF-8']; + yield ['foo BAR Spa', 'foo BAR Spaß', 'ß', 'UTF-8']; + yield ['oo BAR Spaß', 'oo BAR Spaß', 'f', 'UTF-8']; - yield ["oo BAR Spa", "foo BAR Spaß", "ßf", "UTF-8"]; - yield ["oo BAR Spa", "foo BAR Spaß", "fß", "UTF-8"]; - yield ["いうおえお", " あいうおえお あ", " あ", "UTF-8"]; - yield ["いうおえお", " あいうおえお あ", "あ ", "UTF-8"]; - yield [" あいうおえお ", " あいうおえお a", "あa", "UTF-8"]; - yield [" あいうおえお a", " あいうおえお a", "\xe3", "UTF-8"]; + yield ['oo BAR Spa', 'foo BAR Spaß', 'ßf', 'UTF-8']; + yield ['oo BAR Spa', 'foo BAR Spaß', 'fß', 'UTF-8']; + yield ['いうおえお', ' あいうおえお あ', ' あ', 'UTF-8']; + yield ['いうおえお', ' あいうおえお あ', 'あ ', 'UTF-8']; + yield [' あいうおえお ', ' あいうおえお a', 'あa', 'UTF-8']; + yield [' あいうおえお a', ' あいうおえお a', "\xe3", 'UTF-8']; - yield ["", str_repeat(" ", 129)]; - yield ["a", str_repeat(" ", 129) . "a"]; + yield ['', str_repeat(' ', 129)]; + yield ['a', str_repeat(' ', 129).'a']; - yield ["", " \f\n\r\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"]; + yield ['', " \f\n\r\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"]; yield [' abcd ', ' abcd ', '']; @@ -285,19 +285,19 @@ public static function mbLTrimProvider(): iterable yield ['いああああ', 'あああああああああああああああああああああああああああああああああいああああ', 'あ']; - yield ["漢字", "\u{FFFE}漢字", "\u{FFFE}\u{FEFF}"]; + yield ['漢字', "\u{FFFE}漢字", "\u{FFFE}\u{FEFF}"]; yield [' abcd ', ' abcd ', '']; } public static function mbRTrimProvider(): iterable { yield ['ABC', 'ABC']; - yield ["ABC", "ABC \0\t\n"]; + yield ['ABC', "ABC \0\t\n"]; yield ["\0\t\nABC \0\t\n", "\0\t\nABC \0\t\n", '']; yield ['', '']; - yield [" a", str_repeat(" ", 129) . "a"]; + yield [' a', str_repeat(' ', 129).'a']; yield ['あああああああああああああああああああああああああああああああああい', 'あああああああああああああああああああああああああああああああああいああああ', 'あ'];