diff --git a/src/Symfony/Component/String/Inflector/SpanishInflector.php b/src/Symfony/Component/String/Inflector/SpanishInflector.php new file mode 100644 index 0000000000000..4b98cb627bb15 --- /dev/null +++ b/src/Symfony/Component/String/Inflector/SpanishInflector.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Inflector; + +final class SpanishInflector implements InflectorInterface +{ + /** + * A list of all rules for pluralise. + * + * @see https://www.spanishdict.com/guide/spanish-plural-noun-forms + * @see https://www.rae.es/gram%C3%A1tica/morfolog%C3%ADa/la-formaci%C3%B3n-del-plural-plurales-en-s-y-plurales-en-es-reglas-generales + */ + // First entry: regex + // Second entry: replacement + private const PLURALIZE_REGEXP = [ + // Specials sí, no + ['/(sí|no)$/i', '\1es'], + + // Words ending with vowel must use -s (RAE 3.2a, 3.2c) + ['/(a|e|i|o|u|á|é|í|ó|ú)$/i', '\1s'], + + // Word ending in s or x and the previous letter is accented (RAE 3.2n) + ['/ás$/i', 'ases'], + ['/és$/i', 'eses'], + ['/ís$/i', 'ises'], + ['/ós$/i', 'oses'], + ['/ús$/i', 'uses'], + + // Words ending in -ión must changed to -iones + ['/ión$/i', '\1iones'], + + // Words ending in some consonants must use -es (RAE 3.2k) + ['/(l|r|n|d|j|s|x|ch|y)$/i', '\1es'], + + // Word ending in z, must changed to ces + ['/(z)$/i', 'ces'], + ]; + + /** + * A list of all rules for singularize. + */ + private const SINGULARIZE_REGEXP = [ + // Specials sí, no + ['/(sí|no)es$/i', '\1'], + + // Words ending in -ión must changed to -iones + ['/iones$/i', '\1ión'], + + // Word ending in z, must changed to ces + ['/ces$/i', 'z'], + + // Word ending in s or x and the previous letter is accented (RAE 3.2n) + ['/(\w)ases$/i', '\1ás'], + ['/eses$/i', 'és'], + ['/ises$/i', 'ís'], + ['/(\w{2,})oses$/i', '\1ós'], + ['/(\w)uses$/i', '\1ús'], + + // Words ending in some consonants and -es, must be the consonants + ['/(l|r|n|d|j|s|x|ch|y)e?s$/i', '\1'], + + // Words ended with vowel and s, must be vowel + ['/(a|e|i|o|u|á|é|ó|í|ú)s$/i', '\1'], + ]; + + private const UNINFLECTED_RULES = [ + // Words ending with pies (RAE 3.2n) + '/.*(piés)$/i', + ]; + + private const UNINFLECTED = '/^(lunes|martes|miércoles|jueves|viernes|análisis|torax|yo|pies)$/i'; + + public function singularize(string $plural): array + { + if ($this->isInflectedWord($plural)) { + return [$plural]; + } + + foreach (self::SINGULARIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + + if (1 === preg_match($regexp, $plural)) { + return [preg_replace($regexp, $replace, $plural)]; + } + } + + return [$plural]; + } + + public function pluralize(string $singular): array + { + if ($this->isInflectedWord($singular)) { + return [$singular]; + } + + foreach (self::PLURALIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + + if (1 === preg_match($regexp, $singular)) { + return [preg_replace($regexp, $replace, $singular)]; + } + } + + return [$singular.'s']; + } + + private function isInflectedWord(string $word): bool + { + foreach (self::UNINFLECTED_RULES as $rule) { + if (1 === preg_match($rule, $word)) { + return true; + } + } + + return 1 === preg_match(self::UNINFLECTED, $word); + } +} diff --git a/src/Symfony/Component/String/Tests/Inflector/SpanishInflectorTest.php b/src/Symfony/Component/String/Tests/Inflector/SpanishInflectorTest.php new file mode 100644 index 0000000000000..f0b8e4201684d --- /dev/null +++ b/src/Symfony/Component/String/Tests/Inflector/SpanishInflectorTest.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Tests\Inflector; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\String\Inflector\SpanishInflector; + +class SpanishInflectorTest extends TestCase +{ + public static function singularizeProvider(): array + { + return [ + // vowels (RAE 3.2a, 3.2c) + ['peras', 'pera'], + ['especies', 'especie'], + ['álcalis', 'álcali'], + ['códigos', 'código'], + ['espíritus', 'espíritu'], + + // accented (RAE 3.2a, 3.2c) + ['papás', 'papá'], + ['cafés', 'café'], + ['isrealís', 'isrealí'], + ['burós', 'buró'], + ['tisús', 'tisú'], + + // ending in -ión + ['aviones', 'avión'], + ['camiones', 'camión'], + + // ending in some letters (RAE 3.2k) + ['amores', 'amor'], + ['antifaces', 'antifaz'], + ['atriles', 'atril'], + ['fácsimiles', 'fácsimil'], + ['vides', 'vid'], + ['reyes', 'rey'], + ['relojes', 'reloj'], + ['faxes', 'fax'], + ['sándwiches', 'sándwich'], + ['cánones', 'cánon'], + + // (RAE 3.2n) + ['adioses', 'adiós'], + ['aguarrases', 'aguarrás'], + ['arneses', 'arnés'], + ['autobuses', 'autobús'], + ['kermeses', 'kermés'], + ['palmareses', 'palmarés'], + ['toses', 'tos'], + + // Special + ['síes', 'sí'], + ['noes', 'no'], + ]; + } + + public static function pluralizeProvider(): array + { + return [ + // vowels (RAE 3.2a, 3.2c) + ['pera', 'peras'], + ['especie', 'especies'], + ['álcali', 'álcalis'], + ['código', 'códigos'], + ['espíritu', 'espíritus'], + + // accented (RAE 3.2a, 3.2c) + ['papá', 'papás'], + ['café', 'cafés'], + ['isrealí', 'isrealís'], + ['buró', 'burós'], + ['tisú', 'tisús'], + + // ending in -ión + ['avión', 'aviones'], + ['camión', 'camiones'], + + // ending in some letters (RAE 3.2k) + ['amor', 'amores'], + ['antifaz', 'antifaces'], + ['atril', 'atriles'], + ['fácsimil', 'fácsimiles'], + ['vid', 'vides'], + ['rey', 'reyes'], + ['reloj', 'relojes'], + ['fax', 'faxes'], + ['sándwich', 'sándwiches'], + ['cánon', 'cánones'], + + // (RAE 3.2n) + ['adiós', 'adioses'], + ['aguarrás', 'aguarrases'], + ['arnés', 'arneses'], + ['autobús', 'autobuses'], + ['kermés', 'kermeses'], + ['palmarés', 'palmareses'], + ['tos', 'toses'], + + // Specials + ['sí', 'síes'], + ['no', 'noes'], + ]; + } + + public static function uninflectedProvider(): array + { + return [ + ['lunes'], + ['rodapiés'], + ['reposapiés'], + ['miércoles'], + ['pies'], + ]; + } + + /** + * @dataProvider singularizeProvider + */ + public function testSingularize(string $plural, $singular) + { + $this->assertSame( + \is_array($singular) ? $singular : [$singular], + (new SpanishInflector())->singularize($plural) + ); + } + + /** + * @dataProvider pluralizeProvider + */ + public function testPluralize(string $singular, $plural) + { + $this->assertSame( + \is_array($plural) ? $plural : [$plural], + (new SpanishInflector())->pluralize($singular) + ); + } + + /** + * @dataProvider uninflectedProvider + */ + public function testUninflected(string $word) + { + $this->assertSame( + \is_array($word) ? $word : [$word], + (new SpanishInflector())->pluralize($word) + ); + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy