From cfebb09854901fca5055a7d5fc2439c9e8901503 Mon Sep 17 00:00:00 2001 From: Stakovicz Date: Wed, 2 Apr 2025 08:37:20 +0200 Subject: [PATCH] [String] Fix snake function --- .../String/AbstractUnicodeString.php | 15 ++++++++++++--- src/Symfony/Component/String/ByteString.php | 16 +++++++++++++--- .../String/Tests/AbstractAsciiTestCase.php | 19 ++++++++++++------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/String/AbstractUnicodeString.php b/src/Symfony/Component/String/AbstractUnicodeString.php index 70598e4099d72..b8e2125767e93 100644 --- a/src/Symfony/Component/String/AbstractUnicodeString.php +++ b/src/Symfony/Component/String/AbstractUnicodeString.php @@ -346,10 +346,19 @@ public function reverse(): static public function snake(): static { - $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; - return $str; + // space numbers + $str->string = preg_replace('/\d+/u', ' $0 ', $str->string); + // split words + $str->string = preg_replace(['/(\p{Lu}+)(\p{Lu}\p{Ll})/u', '/([\p{Ll}0-9])(\p{Lu})/u'], '\1 \2', $str->string); + // clean spaces + $str->string = preg_replace(['/[^\pL0-9]++/u', '/( {2,})/u'], ' ', $str->string); + + return $str->trimStart() + ->trimEnd() + ->replace(' ', '_') + ->lower(); } public function title(bool $allWords = false): static diff --git a/src/Symfony/Component/String/ByteString.php b/src/Symfony/Component/String/ByteString.php index 3ebe43c10a64a..dbd521a8aa81b 100644 --- a/src/Symfony/Component/String/ByteString.php +++ b/src/Symfony/Component/String/ByteString.php @@ -342,10 +342,20 @@ public function slice(int $start = 0, ?int $length = null): static public function snake(): static { - $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; - return $str; + $str->string = preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $str->string); + // space numbers + $str->string = preg_replace('/(\d+)/', ' $1 ', $str->string); + // split words + $str->string = preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1 \2', $str->string); + // clean spaces + $str->string = preg_replace('/( {2,})/', ' ', $str->string); + + return $str->trimStart() + ->trimEnd() + ->replace(' ', '_') + ->lower(); } public function splice(string $replacement, int $start = 0, ?int $length = null): static diff --git a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php index 3e3d9709a96f4..a8e480a6dd44b 100644 --- a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php @@ -1071,19 +1071,24 @@ public static function provideSnake() ['symfony_is_great', 'symfony-is-great'], ['symfony_is_great', 'symfony.is.great'], ['symfony_is_great', 'symfonyIsGreat'], - ['symfony5_is_great', 'symfony5IsGreat'], - ['symfony5is_great', 'symfony5isGreat'], + ['symfony_5_is_great', 'symfony5IsGreat'], + ['symfony_5_is_great', 'symfony5isGreat'], ['symfony_is_great', 'Symfony is great'], ['symfony_is_a_great_framework', 'symfonyIsAGreatFramework'], ['symfony_is_great', 'symfonyIsGREAT'], + ['symfony_is_great', 'SYMFONY IS GREAT'], + ['symfony_7_is_great', 'symfony 7 is great'], + ['symfony_7_4_is_great', 'symfony 7.4 is great'], + ['symfony_2000_is_great', 'symfony 2000 is great'], ['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!'], + ['best_symfony_is_2', 'Best Symfony is 2'], ['123_customer_with_special_name', '123-customer,with/special#name'], ]; }