diff --git a/src/Symfony/Component/String/AbstractUnicodeString.php b/src/Symfony/Component/String/AbstractUnicodeString.php index 21aa22e186a64..2861b38d7bb1f 100644 --- a/src/Symfony/Component/String/AbstractUnicodeString.php +++ b/src/Symfony/Component/String/AbstractUnicodeString.php @@ -366,8 +366,23 @@ public function reverse(): parent public function snake(): parent { - $str = $this->camel(); - $str->string = mb_strtolower(preg_replace(['/(\p{Lu}+)(\p{Lu}\p{Ll})/u', '/([\p{Ll}0-9])(\p{Lu})/u'], '\1_\2', $str->string), 'UTF-8'); + $str = clone $this; + $matches = []; + + preg_match_all( + '/([\p{Ll}0-9]+(?=\p{Lu}))|(\p{Lu}[\p{Ll}0-9]+)|(\p{Lu}+(?=\p{Lu}\p{Ll}))|((?<=\w)?[\p{Ll}\p{Lu}0-9]+(?=\w)?)/u', + $str->string, + $matches + ); + + $strings = array_map( + function (string $matchedString) { + return mb_strtolower($matchedString, 'UTF-8'); + }, + $matches[0] ?? [] + ); + + $str->string = implode('_', $strings); return $str; } diff --git a/src/Symfony/Component/String/ByteString.php b/src/Symfony/Component/String/ByteString.php index 05170da801c0e..667ca16e4b149 100644 --- a/src/Symfony/Component/String/ByteString.php +++ b/src/Symfony/Component/String/ByteString.php @@ -366,8 +366,23 @@ public function slice(int $start = 0, ?int $length = null): parent public function snake(): parent { - $str = $this->camel(); - $str->string = strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1_\2', $str->string)); + $str = clone $this; + $matches = []; + + preg_match_all( + '/([a-z0-9]+(?=[A-Z]))|([A-Z][a-z0-9]+)|([A-Z]+(?=[A-Z][a-z]))|((?<=\w)?[a-zA-Z0-9]+(?=\w)?)/', + $str->string, + $matches + ); + + $strings = array_map( + function (string $matchedString) { + return strtolower($matchedString); + }, + $matches[0] ?? [] + ); + + $str->string = implode('_', $strings); return $str; } diff --git a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php index 14727da2394d2..1ac5db008a86b 100644 --- a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php @@ -1080,12 +1080,14 @@ public static function provideSnake() ['symfony_is_great', 'symfonyIsGREAT'], ['symfony_is_really_great', 'symfonyIsREALLYGreat'], ['symfony', 'SYMFONY'], - ['symfonyisgreat', 'SYMFONY IS GREAT'], - ['symfonyisgreat', 'SYMFONY_IS_GREAT'], + ['symfony_is_great', 'SYMFONY IS GREAT'], + ['symfony_is_great', 'SYMFONY_IS_GREAT'], ['symfony_is_great', 'symfony is great'], - ['symfonyisgreat', 'SYMFONY IS GREAT'], - ['symfonyisgreat', 'SYMFONY _ IS _ GREAT'], - ['symfony_isgreat', 'Symfony IS GREAT!'], + ['symfony_is_great', 'SYMFONY IS GREAT'], + ['symfony_is_great', 'SYMFONY _ IS _ GREAT'], + ['symfony_is_great', 'Symfony IS GREAT!'], + ['123_customer_with_special_name', '123-customer,with/special#name'], + ['this_value_should_be_false', 'This value should be false.'], ]; }