44See here https://github.com/clips/pattern/blob/master/LICENSE.txt for
55complete license information.
66"""
7+
8+ from __future__ import annotations
9+ from collections .abc import MutableMapping
710import re
11+ from typing import TYPE_CHECKING
12+
13+ if TYPE_CHECKING :
14+ from typing import AnyStr
15+
816
917VERB , NOUN , ADJECTIVE , ADVERB = "VB" , "NN" , "JJ" , "RB"
1018
523531}
524532
525533
526- def pluralize (word , pos = NOUN , custom = None , classical = True ):
534+ def pluralize (word : str , pos = NOUN , custom = None , classical = True ) -> str :
527535 """Returns the plural of a given word.
528536 For example: child -> children.
529537 Handles nouns and adjectives, using classical inflection by default
@@ -584,6 +592,7 @@ def pluralize(word, pos=NOUN, custom=None, classical=True):
584592 ):
585593 if suffix .search (word ) is not None :
586594 return suffix .sub (inflection , word )
595+ return word
587596
588597
589598#### SINGULARIZE ###################################################################################
@@ -607,55 +616,57 @@ def pluralize(word, pos=NOUN, custom=None, classical=True):
607616# THIS SOFTWARE.
608617
609618singular_rules = [
610- [ "(?i)(.)ae$" , "\\ 1a" ] ,
611- [ "(?i)(.)itis$" , "\\ 1itis" ] ,
612- [ "(?i)(.)eaux$" , "\\ 1eau" ] ,
613- [ "(?i)(quiz)zes$" , "\\ 1" ] ,
614- [ "(?i)(matr)ices$" , "\\ 1ix" ] ,
615- [ "(?i)(ap|vert|ind)ices$" , "\\ 1ex" ] ,
616- [ "(?i)^(ox)en" , "\\ 1" ] ,
617- [ "(?i)(alias|status)es$" , "\\ 1" ] ,
618- [ "(?i)([octop|vir])i$" , "\\ 1us" ] ,
619- [ "(?i)(cris|ax|test)es$" , "\\ 1is" ] ,
620- [ "(?i)(shoe)s$" , "\\ 1" ] ,
621- [ "(?i)(o)es$" , "\\ 1" ] ,
622- [ "(?i)(bus)es$" , "\\ 1" ] ,
623- [ "(?i)([m|l])ice$" , "\\ 1ouse" ] ,
624- [ "(?i)(x|ch|ss|sh)es$" , "\\ 1" ] ,
625- [ "(?i)(m)ovies$" , "\\ 1ovie" ] ,
626- [ "(?i)(.)ombies$" , "\\ 1ombie" ] ,
627- [ "(?i)(s)eries$" , "\\ 1eries" ] ,
628- [ "(?i)([^aeiouy]|qu)ies$" , "\\ 1y" ] ,
619+ ( re . compile ( "(?i)(.)ae$" ) , "\\ 1a" ) ,
620+ ( re . compile ( "(?i)(.)itis$" ) , "\\ 1itis" ) ,
621+ ( re . compile ( "(?i)(.)eaux$" ) , "\\ 1eau" ) ,
622+ ( re . compile ( "(?i)(quiz)zes$" ) , "\\ 1" ) ,
623+ ( re . compile ( "(?i)(matr)ices$" ) , "\\ 1ix" ) ,
624+ ( re . compile ( "(?i)(ap|vert|ind)ices$" ) , "\\ 1ex" ) ,
625+ ( re . compile ( "(?i)^(ox)en" ) , "\\ 1" ) ,
626+ ( re . compile ( "(?i)(alias|status)es$" ) , "\\ 1" ) ,
627+ ( re . compile ( "(?i)([octop|vir])i$" ) , "\\ 1us" ) ,
628+ ( re . compile ( "(?i)(cris|ax|test)es$" ) , "\\ 1is" ) ,
629+ ( re . compile ( "(?i)(shoe)s$" ) , "\\ 1" ) ,
630+ ( re . compile ( "(?i)(o)es$" ) , "\\ 1" ) ,
631+ ( re . compile ( "(?i)(bus)es$" ) , "\\ 1" ) ,
632+ ( re . compile ( "(?i)([m|l])ice$" ) , "\\ 1ouse" ) ,
633+ ( re . compile ( "(?i)(x|ch|ss|sh)es$" ) , "\\ 1" ) ,
634+ ( re . compile ( "(?i)(m)ovies$" ) , "\\ 1ovie" ) ,
635+ ( re . compile ( "(?i)(.)ombies$" ) , "\\ 1ombie" ) ,
636+ ( re . compile ( "(?i)(s)eries$" ) , "\\ 1eries" ) ,
637+ ( re . compile ( "(?i)([^aeiouy]|qu)ies$" ) , "\\ 1y" ) ,
629638 # Certain words ending in -f or -fe take -ves in the plural (lives, wolves).
630- [ "([aeo]l)ves$" , "\\ 1f" ] ,
631- [ "([^d]ea)ves$" , "\\ 1f" ] ,
632- [ "arves$" , "arf" ] ,
633- [ "erves$" , "erve" ] ,
634- [ "([nlw]i)ves$" , "\\ 1fe" ] ,
635- [ "(?i)([lr])ves$" , "\\ 1f" ] ,
636- [ "([aeo])ves$" , "\\ 1ve" ] ,
637- [ "(?i)(sive)s$" , "\\ 1" ] ,
638- [ "(?i)(tive)s$" , "\\ 1" ] ,
639- [ "(?i)(hive)s$" , "\\ 1" ] ,
640- [ "(?i)([^f])ves$" , "\\ 1fe" ] ,
639+ ( re . compile ( "([aeo]l)ves$" ) , "\\ 1f" ) ,
640+ ( re . compile ( "([^d]ea)ves$" ) , "\\ 1f" ) ,
641+ ( re . compile ( "arves$" ) , "arf" ) ,
642+ ( re . compile ( "erves$" ) , "erve" ) ,
643+ ( re . compile ( "([nlw]i)ves$" ) , "\\ 1fe" ) ,
644+ ( re . compile ( "(?i)([lr])ves$" ) , "\\ 1f" ) ,
645+ ( re . compile ( "([aeo])ves$" ) , "\\ 1ve" ) ,
646+ ( re . compile ( "(?i)(sive)s$" ) , "\\ 1" ) ,
647+ ( re . compile ( "(?i)(tive)s$" ) , "\\ 1" ) ,
648+ ( re . compile ( "(?i)(hive)s$" ) , "\\ 1" ) ,
649+ ( re . compile ( "(?i)([^f])ves$" ) , "\\ 1fe" ) ,
641650 # -es suffix.
642- ["(?i)(^analy)ses$" , "\\ 1sis" ],
643- ["(?i)((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$" , "\\ 1\\ 2sis" ],
644- ["(?i)(.)opses$" , "\\ 1opsis" ],
645- ["(?i)(.)yses$" , "\\ 1ysis" ],
646- ["(?i)(h|d|r|o|n|b|cl|p)oses$" , "\\ 1ose" ],
647- ["(?i)(fruct|gluc|galact|lact|ket|malt|rib|sacchar|cellul)ose$" , "\\ 1ose" ],
648- ["(?i)(.)oses$" , "\\ 1osis" ],
651+ (re .compile ("(?i)(^analy)ses$" ), "\\ 1sis" ),
652+ (
653+ re .compile ("(?i)((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$" ),
654+ "\\ 1\\ 2sis" ,
655+ ),
656+ (re .compile ("(?i)(.)opses$" ), "\\ 1opsis" ),
657+ (re .compile ("(?i)(.)yses$" ), "\\ 1ysis" ),
658+ (re .compile ("(?i)(h|d|r|o|n|b|cl|p)oses$" ), "\\ 1ose" ),
659+ (
660+ re .compile ("(?i)(fruct|gluc|galact|lact|ket|malt|rib|sacchar|cellul)ose$" ),
661+ "\\ 1ose" ,
662+ ),
663+ (re .compile ("(?i)(.)oses$" ), "\\ 1osis" ),
649664 # -a
650- [ "(?i)([ti])a$" , "\\ 1um" ] ,
651- [ "(?i)(n)ews$" , "\\ 1ews" ] ,
652- [ "(?i)s$" , "" ] ,
665+ ( re . compile ( "(?i)([ti])a$" ) , "\\ 1um" ) ,
666+ ( re . compile ( "(?i)(n)ews$" ) , "\\ 1ews" ) ,
667+ ( re . compile ( "(?i)s$" ) , "" ) ,
653668]
654669
655- # For performance, compile the regular expressions only once:
656- for rule in singular_rules :
657- rule [0 ] = re .compile (rule [0 ])
658-
659670singular_uninflected = [
660671 "aircraft" ,
661672 "antelope" ,
@@ -833,7 +844,7 @@ def pluralize(word, pos=NOUN, custom=None, classical=True):
833844}
834845
835846
836- def singularize (word , pos = NOUN , custom = None ):
847+ def singularize (word : str , pos = NOUN , custom : MutableMapping [ str , str ] | None = None ):
837848 if custom is None :
838849 custom = {}
839850 if word in list (custom .keys ()):
0 commit comments