diff options
| -rw-r--r-- | .classpath | 31 | ||||
| -rw-r--r-- | data/nouns.txt | 2759 | ||||
| -rw-r--r-- | data/prepositions.txt | 51 | ||||
| -rw-r--r-- | src/examples/java/bjc/inflexion/InflexionTester.java | 67 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/CategoricalNounInflection.java | 204 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/CompoundNounInflection.java | 170 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/DefaultNounInflection.java | 68 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/InflectionAffix.java | 56 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/InflectionAffixes.java | 74 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/InflectionException.java | 49 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/IrregularNounInflection.java | 197 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/Noun.java | 121 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/NounInflection.java | 113 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/Nouns.java | 183 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/Prepositions.java | 71 | ||||
| -rw-r--r-- | src/main/java/bjc/inflexion/v2/SimpleInflectionAffix.java | 103 |
16 files changed, 4302 insertions, 15 deletions
@@ -1,15 +1,16 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src/main/java"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
- <attributes>
- <attribute name="maven.pomderived" value="true"/>
- </attributes>
- </classpathentry>
- <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
- <attributes>
- <attribute name="maven.pomderived" value="true"/>
- </attributes>
- </classpathentry>
- <classpathentry kind="output" path="target/classes"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src/main/java"/> + <classpathentry kind="src" path="src/examples/java"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/data/nouns.txt b/data/nouns.txt new file mode 100644 index 0000000..fb976ab --- /dev/null +++ b/data/nouns.txt @@ -0,0 +1,2759 @@ +# Words that inflect singular->plural normally +# but which are ambiguous when inflected plural->singular... +# (e.g. "axes"-->"ax" vs "axes"-->"axe" vs "axes"-->"axis") +# [These need to be at the start so the rest of the inflections defer to them] +# [The first form in each group is always preferred] + +agendum => | agenda +agend => agends | agenda + +axe => axes +ax => axes + +base => bases +basis => bases + +blue => blues +blues => blues + +breech => breeches +breeches => breeches + +clippers => clippers +clipper => clippers + +co => coes +coe => coes + +coney => coneys | conies +cony => conys | conies + +doe => does +do => does + +ellipse => ellipses +ellipsis => ellipses + +fro => froes +froe => froes + +genie => genies | genii +genius => geniuses | genii + +glass => glasses +glasses => glasses + +graffiti => graffiti +graffito => graffiti + +heroon => heroa +heroum => heroa + +hoe => hoes +ho => hoes + +joe => joes +jo => joes + +mew => mews +mews => mews + +moe => moes +mo => moes + +monsignore => | monsignori +monsignor => monsignors | monsignori + +pant => pants +pants => pants + +penny => pennies | pence +pence => pence + +pincer => pincers +pincers => pincers + +po => poes +poe => poes + +shears => shears +shear => shears + +shorts => shorts +short => shorts + +so => soes +soe => soes + +*staff => *staffs | *staves +*stave => *staves + +syringe => syringes +syrinx => syrinxes | syringes + +testes => testes +testis => testes + +toe => toes +to => toes + +tongs => tongs +tong => tongs + +yo => yoes +yoe => yoes + + +# Singular words ending in "-s" with irregular inflexions... + +Atlas => | Atlantes +atlas => atlases | atlantes +editio princeps => | editiones principes +eros => eroses | erotes +gens => | gentes +maecenas => maecenases | maecenates +mons => | montes +Nenets => Nenets | Nentsi +paries => | parietes +potestas => | potestates +proferens => | proferentes +secans => | secantes +starets => | startsy +triens => | trientes +venus => venuses | veneres +yes => yeses | + + +# Latin imports ending in "-us" that classically inflect to "-era"... + +*genus => | genera +glomus => | glomera +opus => opuses | opera +# Classical should be "opera", but it's ambiguous +viscus => | viscera + + +# Compound words (mostly imported) that inflect irregularly (for English)... + +agent provocateur => | agents provocateurs +aide-de-camp => | aides-de-camp +ale-wife => ale-wives | +alto-relievo => alto-relievos | +amicus curiae => | amici curiae +anti-serum => anti-serums | anti-sera +auto-de-fe => auto-de-fes | autos-de-fes +beau geste => beau gestes | beaux gestes +bel homme => | beaux hommes +bel-esprit => | beaux esprits +belle epoque => belle epoques | belles epoques +bon mot => bon mots | bons mots +bon vivant => bon vivants | bons vivants +bona fides => | bonis fidebus +break-away => break-aways | breaks-away +brother-german => brothers-german | brethren-german +caffe macchiato => caffe macchiatos | caffe macchiati +caffe ristretto => caffe ristrettos | caffe ristretti +camera obscura => camera obscuras | camerae obscurae +carte-de-visite => | cartes-de-visite +casus belli => | casus belli +cheval-de-bataille => | chevaux-de-bataille +collegium musicum => | collegia musica +concerto grosso => | concerti grossi +corpus vile => | corpora vilia +coup d'etat => | coups d'etat +court martial => court-martials | courts martial +crafts-child => | crafts-childer +cri de coeur => | cris de coeur +cul-de-four => | culs-de-four +cul-de-lampe => | culs-de-lampe +cul-de-sac => | culs-de-sac +editio princeps => | editiones principes +ens rationis => | entia rationis +ens reale => | entia realia +entente cordiale => | ententes cordiales +fait accompli => | faits accomplis +felo-de-se => felos-de-se | felones-de-se +fidei defensor => | fidei defensores +finger-end => finger-ends | fingers-ends +flag-staff => flag-staffs | flag-staves +franc-archer => franc-archers | francs-archers +fundamentum divisionis => | fundamenta divisionis +fungo porcino => | funghi porchini +guardia civil => | guardias civiles +hapax legomenon => hapax legomenons | hapax legomena +hemi-elytrum => | hemi-elytra +idee fixe => | idees fixes +infima species => | infimae species +ipse dixit => | ipse dixits +lex humana => | leges humanae +line-out => line-outs | lines-out +lord-lieutenant => lord-lieutenants | lords-lieutenant +magnum opus => magnum opuses | magna opera +malum in se => | mala in se +man-child => men-children | +man-midwife => men-midwives | +man-milliner => man-milliners | men-milliners +man-servant => | men-servants +mater lectionis => | matres lectionis +matinee musicale => | matinees musicales +menage a quatre => | menages a quatre +menage a trois => | menages a trois +messa di voce => | messe di voce +mezzo-rilievo => | mezzo-rilievos +miles gloriosus => | milites gloriosi +milieu interieur => | milieux interieurs +monstre sacre => | monstres sacres +musee imaginaire => | musees imaginaires +musique concrete => | musiques concretes +naya paisa => | naye paise +non-ens => | nonentia +nouveau pauvre => nouvelle pauvre | nouveaux pauvres +nouveau riche => nouvelle riche | nouveaux riches +nouvel arrive => | nouveaux arrives +novus homo => | novi homines +opus magnum => | opera magna +parc ferme => | parcs fermes +pied a terre => | pieds a terre +pied noir => | pieds noirs +pina colada => pina coladas | pinas coladas +plurale tantum => | pluralia tantum +pomme de terre => | pommes de terre +port de bras => | ports de bras +port-a-beul => | puirt-a-beul +portrait parle => | portraits parles +premier danseur => | premiers danseurs +prima ballerina => prima ballerinas | prime ballerine +prima donna => prima donnas | prime donne +punto blanco => puntos blancos | punti blanchi +rara avis => rara avises | rarae aves +rite de passage => | rites de passage +rond de jambe => rond de jambes | ronds de jambes +route nationale => | routes nationales +ruse de guerre => | ruses de guerre +sanctum sanctorum => | sancta sanctorum +scandalum magnatum => | scandala magnatum +set-off => set-offs | sets-off +set-out => set-outs | sets-out +set-to => set-tos | sets-to +star-fish => star-fishes | star-fish +studium generale => | studia generali +suggestio falsi => | suggestiones falsi +summum bonum => | summa bona +summum genus => | summa genera +sum-total => sum-totals | sums-total +terrae filius => | terrae filii +tete-a-tete => tete-a-tetes | +tortilla espanola => | tortillas espanolas +tour de force => | tours de force +uomo universale => | uomini universali +varia lectio => | variae lectiones +vers libre => | vers libres +washer-up => washers-up | +white staff => white staves | +woman-child => women-children | +woman-servant => women-servants | + + +# Other words with irregular inflexions... + +alan => alans | alani +atman => atmas | +bajocco => | bajocchi +bandit => bandits | banditti +bersagliere => | bersaglieri +blin => blinis | blini +blouse => blouses | +brachiopod => brachiopods | brachiopoda +branchiopod => branchiopods | branchiopoda +breakaway => breakaways | breaksaway +brother-german => brothers-german | brethren-german +calzone => calzones | calzoni +capo => capos | capi +caryatid => caryatids | caryatides +chervonetz => | chervontzi +cony => conys | conies +court-martial => court-martials | courts-martial +curioso => curiosos | curiosi +devoto => devotos | devoti +die => dice | dies +divertimento => divertimentos | divertimenti +fedai => fedais | fedai +ganglion => ganglions | ganglia +giuncus => | giunchi +glutaeus => glutei | glutaei +gluteus => glutei | glutaei +graffiti => graffiti | +graffito => graffiti | +hamadryad => hamadrayads | hamadryades +hetaera => hetaerae | hetairai +hetaira => hetaerae | hetairai +hinaki => | hinaki +ixodid => | ixodides +jerry => jerries | +Jerry => Jerrys | +kovsh => | kovshi +kuvasz => | kuvaszok +laika => | laiki +Lapith => Lapiths | Lapithae +leu => | lei +likuta => | makuta +maestro => maestros | maestri +mare => mares | maria +mary => maries | +Mary => Marys | +matzah => matzahs | matzot +modello => modellos | modelli +money => monies | +monseigneur => monsiegneurs | messeigneurs +mousetrap => mousetraps | micetraps +nagaika => nagaikas | nagaiki +niello => niellos | nielli +occiput => occiputs | occipita +octopus => octopuses | +# Not correct, but widely used +octopus => | octopi +# Not correct either, and rarely used +octopus => | octopodes +onager => onagers | onagri +otomi => otomies | otomi +pecten => pectens | pectines +penni => | pennia +*person => people | persons +plankter => plankton | +platypus => platypuses | platypodes +ploshchadka => | ploshchadki +pul => puls | puli +rezidentsia => | rezidentsii +ricercar => ricercars | ricercari +ritardando => ritardandos | ritardandi +Rom => Roma | +Romany => Romanies | +rubashka => rubashkas | rubashki +scirrhus => scirrhusses | scirrhi +scomber => scombri | +sforzato => sforzatos | sforzati +siglos => sigli | sigloi +ski => skis | +solfeggio => solfeggios | solfeggi +squadrist => squadrists | squadristi +staretz => | startzy +starosta => | starosti +stoa => stoas | stoai +storey => storeys | +tolkach => | tolkachi +trilby => trilbys | +udarnik => | udarniki +valuta => valute | valuten +zloty => zlotys | zloty + + + +# Units that don't inflect... + +*hertz => hertz +*lux => lux +*siemens => siemens + + +# Currencies that don't inflect... + +kobo => kobo +ngwee => ngwee +quid => quid +thebe => thebe + + +# Miscellaneous words that inflect normally (but classically don't inflect at all)... + +djinn => djinns | djinn +Galla => Gallas | Galla +graben => grabens | graben +lis => lisses | lis +listeria => listerias | listeria +loa => loas | loa +lox => loxes | lox +microfiche => microfiches | microfiche +Otomi => Otomies | Otomi +poise => poises | poise +Purum => Purums | Purum +rad => rads | rad +rem => rems | rem +shifta => shiftas | shifta +torma => tormas | torma +veg => veges | veg + + +# Words of Old English or Germanic origin that classically inflect to "-en" or "-ne"... + +anlage => anlages | anlagen +auslese => ausleses | auslesen +autobahn => autobahns | autobahnen +*brother => brothers | brethren +*child => | children +*cow => cows | kine +erf => erfs | erven +knopper => knoppers | knoppern +konditorei => konditorei | konditoreien +manchild => | menchildren +ox => | oxen +--ox => | --oxen +romanze => | romanzen +terp => terps | terpen +vlakte => vlaktes | vlakten +womanchild => | womenchildren + + +# German imports that retain their native -en plurals... + +Auslese => Auslesen +beerenauslese => beerenauslesen +bursch => burschen +geisteswissenschaft => geisteswissenschaften +herr => herren +lebensform => lebensformen +*mensch => *menschen +Spaetlese => Spaetlesen +trockenbeerenauslese => trockenbeerenauslesen +umwelt => umwelten +vorstellung => vorstellungen + + +# Russian imports that classically inflect natively... + +apparatchik => apparatchiks | apparatchiki +ispravnik => ispravniks | ispravniki +subbotnik => subbotniks | subbotniki + + +# Words ending in unvoiced fricatives that classically inflect to voiced... + +beef => beefs | beeves +*elf => | elves +*hoof => hoofs | hooves +*knife => | knives +*leaf => | leaves +*life => | lives +*loaf => | loaves +*shelf => | shelves +*thief => | thieves +turf => turfs | turves +wharf => wharfs | wharves +*wife => | wives +*wolf => | wolves + + +# Words whose suffixes are normally ablaut, but not in these words... + +ataman => atamans +Bahaman => Bahamans +Burman => Burmans +caiman => caimans +cayman => caymans +ceriman => cerimans +crowfoot => crowfoots +desman => desmans +dolman => dolmans +fanfoot => fanfoots +farman => farmans +flatfoot => flatfoots +German => Germans +harman => harmans +hetman => hetmans +Hiroshiman => Hiroshimans +*human => humans +leman => lemans +Liman => Limans +lowlife => lowlifes +mongoose => mongooses +Nakayaman => Nakayamans +Norman => Normans +Oklahoman => Oklahomans +ottoman => ottomans +Panaman => Panamans +Roman => Romans +sabertooth => sabertooths +Selman => Selmans +shaman => shamans +Sonaman => Sonamans +switchfoot => switchfoots +Tacoman => Tacomans +talisman => talismans +talouse => talouses +tenderfoot => tenderfoots +Yakiman => Yakimans +Yokohaman => Yokohamans +Yuman => Yumans + +# Words whose suffixes are ablaut, but not classically... + +yarraman => yarramen | yarramans +dragoman => dragomen | dragomans + +# Words with ablaut plurals... + +*foot => feet +*goose => geese +*louse => lice +*man => men +manservant => menservants +*mouse => mice +*tooth => teeth + + +# Words ending in "-z" and "-ze" that don't double the "z" for the plural... + +batz => batzes +blitz => blitzes +chintz => chintzes +coz => cozes +quartz => quartzes +snooze => snoozes +topaz => topazes +waltz => waltzes + + +# Words whose plurals end in "-zzes" but whose singulars end in "-zz"... + +*buzz => buzzes +*fizz => fizzes +*frizz => frizzes +*fuzz => fuzzes +*jazz => jazzes +muzz => muzzes +razz => razzes +sizz => sizzes +zizz => zizzes + + +# Greek imports ending in "-x" that classically inflect to "-kes" + +larnax => | larnakes +kylix => kylixes | kylikes + + +# Greek imports ending in "-os" that always inflect to "-oi" + +kantharos => kantharoi +kernos => kernoi +kouros => kouroi +mythos => mythoi +phallos => phalloi +pharmakos => pharmakoi +pithos => pithoi +stichos => stichoi +strategos => strategoi +thalamos => thalamoi +tholos => tholoi +topos => topoi + + +# Greek imports ending in "-s" that classically inflect to "-des" + +aphis => | aphides +apsis => | apsides +caryopsis => | caryopsides +chrysalis => chrysalises | chrysalides +cinclis => | cinclides +clitoris => clitorises | clitorides +cuspis => | cuspides +dipsas => | dipsades +ephelis => | ephelides +ephemeris => ephemerises | ephemerides +epididymis => epididymises | epididymides +iris => irises | irides +meliceris => | melicerides +meris => | merides +monas => | monades +monorchis => | monorchides +oxyuris => | oxyurides +parapsis => | parapsides +pes => | pedes +pholas => | pholades +*proboscis => proboscises | proboscides +proglottis => | proglottides +pycnis => | pycnides +pyralis => | pyralides +tropis => | tropides +vasculitis => vasculitises | vasculitides + +# Greek imports ending in "-es" that classically inflect to "-ites" + +fomes => | fomites +limes => | limites +satelles => | satellites +stipes => | stipites +termes => | termites + +# Greek imports ending in "-a" that classically inflect to "-ata" + +acroama => | acroamata +anathema => anathemas | anathemata +angioma => | angiomata +astrocytoma => astrocytomas | astrocytomata +*bema => bemas | bemata +blastema => | blastemata +bregma => | bregmata +carcinoma => carcinomas | carcinomata +cathisma => | cathismata +cementoma => | cementomata +charisma => charismas | charismata +chromonema => | chromonemata +cystoma => | cystomata +desma => desmas | desmata +diastema => | diastemata +diploma => diplomas | diplomata +dogma => dogmas | dogmata +*drama => dramas | +*edema => edemas | edemata +emblema => | emblememata +embryoma => | embryomata +endothelioma => | endotheliomata +enema => enemas | enemata +enigma => enigmas | enigmata +epithelioma => | epitheliomata +exanthema => | exanthemata +fibroma => | fibromata +glioma => | gliomata +gliosarcoma => | gliosarcomata +gumma => gummas | gummata +haemangioma => haemangiomas | haemangiomata +hemangeioma => hemangeiomas | hemangeiomata +hemangioma => hemangiomas | hemangiomata +hypoderma => | hypodermata +*lemma => lemmas | lemmata +leproma => lepromas | lepromata +lipoma => | lipomata +loma => | lomata +lymphangioma => | lymphangiomata +lymphoma => lymphomas | lymphomata +magma => magmas | magmata +malagma => | malagmata +medulloblastoma => medulloblastomas | medulloblastomata +melanoma => melanomas | melanomata +melisma => melismas | melismata +meningioma => meningiomas | meningiomata +mesothelioma => mesotheliomas | mesotheliomata +miasma => miasmas | miasmata +mycoplasma => mycoplasmas | mycoplasmata +myeloma => myelomas | myelomata +myxoma => | myxomata +neuma => neumas | neumata +neurinoma => neurinomas | neurinomata +neuroma => | neuromata +noema => | noemata +nomisma => | nomismata +nucleolonema => nucleolonemas | nucleolonemata +oedema => oedemas | oedemata +osteoclastoma => osteoclastomas | osteoclastomata +osteoma => | osteomata +papilloma => | papillomata +paraganglioma => paragangliomas | paragangliomata +parenchyma => | parenchymata +phragma => | phragmata +phyma => | phymata +plasmoma => | plasmomata +pragma => pragmas | pragmata +programma => | programmata +progymnasma => | progymnasmata +protonema => | protonemata +psammoma => | psammomata +pseudostoma => | pseudostomata +pteroma => | pteromata +regma => | regmata +rhinophyma => rhinophymas | rhinophymata +rhizoma => rhizomas | rhizomata +*sarcoma => sarcomas | sarcomata +schema => schemas | schemata +schisma => | schismata +scotoma => scotomas | scotomata +sema => semas | semata +soma => somas | somata +sperma => | spermata +stemma => | stemmata +sterigma => | sterigmata +stigma => stigmas | stigmata +*stoma => stomas | stomata +stroma => | stromata +symplasma => | symplasmata +syntagma => syntagmas | syntagmata +syphiloma => | syphilomata +tagma => | tagmata +teratoma => | teratomata +thema => | themata +toxoplasma => | toxoplasmata +trauma => traumas | traumata +treponema => | treponemata +trichoma => | trichomata +tuberculoma => tuberculomas | tuberculomata +xanthoma => xanthomas | xanthomata +zygoma => zygomas | zygomata + + +# Latin imports ending in "-a" that classically inflect to "-ae"... + +abscissa => abscissas | abscissae +acicula => | aciculae +actinia => actinias | actiniae +agape => agapes | agapae +agora => | agorae +ala => | alae +alga => | algae +alula => | alulae +alumna => | alumnae +amoeba => amoebas | amoebae +amphora => | amphorae +angustia => | angustiae +anta => | antae +antenna => antennas | antennae +areola => | areolae +arista => | aristae +arrha => | arrhae +asterias => | asteriae +aurora => auroras | aurorae +axilla => | axillae +ballista => ballistas | ballistae +basilica => basilicas | basilicae +blemya => | blemyae +bulla => | bullae +bursa => | bursae +cavea => | caveae +celia => | celiae +chaeta => | chaetae +chlamydia => chlamydias | chlamydiae +choana => | choanae +chorda => | chordae +clausula => | clausulae +clavula => | clavulae +clepsydra => clepsydras | clepsydrae +coelia => | coeliae +columna => | columnae +coma => | comae +comatula => | comatulae +conferva => | confervae +corona => coronas | coronae +costa => | costae +crista => | cristae +crusta => | crustae +cyphella => | cyphellae +differentia => | differentiae +diporpa => | diporpae +ephemera => ephemeras | ephemerae +fabella => | fabellae +faecula => | faeculae +familia => | familiae +fascia => fascias | fasciae +fauna => faunas | faunae +favella => | favellae +favissa => | favissae +fecula => | feculae +fenestra => | fenestrae +fibra => | fibrae +fibrilla => | fibrillae +fibula => fibulas | fibulae +filaria => filarias | filariae +flora => floras | florae +formula => formulas | formulae +fossa => | fossae +gemma => | gemmae +gena => | genae +globigerina => | globigerinae +gorgonia => gorgonias | gorgoniae +granula => | granulae +hemera => | hemerae +hernia => hernias | herniae +holothuria => holothurias | holothuriae +hydra => hydras | hydrae +hydria => | hydriae +hyperbola => hyperbolas | hyperbolae +hypha => | hyphae +indigena => | indigenae +insula => | insulae +intermaxilla => | intermaxillae +lacinia => | laciniae +lacuna => lacunas | lacunae +lamella => | lamellae +lamina => | laminae +lapith => lapiths | lapithae +legionella => | legionellae +leishmania => leishmanias | leishmaniae +leptospira => | leptospirae +linea => | lineae +lingula => | lingulae +listerella => listerellas | listerellae +lyssa => | lyssae +macula => maculas | maculae +maxilla => | maxillae +medusa => medusas | medusae +melastoma => melastomas | melastomae +meta => | metae +miliola => | miliolae +mimosa => mimosas | mimosae +minutia => minutias | minutiae +monota => | monotae +multigravida => multigravidas | multigravidae +musa => musas | musae +mya => myas | myae +mycorhiza => mycorhizas | mycorhizae +mycorrhiza => mycorrhizas | mycorrhizae +naumachia => naumachias | naumachiae +nebula => nebulas | nebulae +nerita => neritas | neritae +neurula => | neurulae +noctiluca => | noctilucae +*nova => novas | novae +noxa => | noxae +nubecula => | nubeculae +nympha => | nymphae +pala => | palae +palea => | paleae +palpebra => | palpebrae +panorpa => | panorpae +papilla => | papillae +papula => | papulae +parabola => parabolas | parabolae +paraglossa => | paraglossae +parapleura => parapleura +paraselene => | paraselenae +pasteurella => pasteurellas | pasteurellae +patera => | paterae +paxilla => | paxillae +pecia => pecias | peciae +pedicellaria => | pedicellariae +pelta => | peltae +peninsula => peninsulas | peninsulae +persona => personas | personae +phlegmasia => | phlegmasiae +phoca => phocas | phocae +phyle => | phylae +phyllobranchia => | phyllobranchiae +pinna => pinnas | pinnae +piscina => piscinas | piscinae +planula => | planulae +plasmalemma => plasmalemmas | plasmalemmae +pleura => pleura | +plica => | plicae +prepenna => | prepennae +primigravida => | primigravidae +procoelia => | procoeliae +prora => | prorae +prosa => | prosae +proscolla => | proscollae +proseucha => | proseuchae +prosula => | prosulae +protoma => protomas | protomae +pteryla => | pterylae +pupa => | pupae +pyla => | pylae +pyrexia => | pyrexiae +redia => | rediae +retinula => | retinulae +rotula => | rotulae +ruga => | rugae +salpa => salpas | salpae +sarcina => | sarcinae +sarissa => | sarissae +saxicava => | saxicavae +scapula => scapulas | scapulae +scoria => scorias | scoriae +secundagravida => secundagravidas | secundagravidae +secundigravida => secundigravidas | secundigravidae +secundipara => secundiparas | secundiparae +semuncia => | semunciae +sententia => | sententiae +sequela => | sequelae +serpula => | serpulae +serra => | serrae +sertularia => sertularias | sertulariae +seta => | setae +siliqua => | siliquae +simia => | simiae +situla => situlas | situlae +spatha => | spathae +spermatheca => | spermathecae +squama => | squamae +squilla => | squillae +stalactite => stalactites | stalactitae +statera => | staterae +statua => statuas | statuae +stela => stelas | stelae +stella => | stellae +sternebra => | sternebrae +stigmaria => | stigmariae +stipula => stipulas | stipulae +stria => | striae +striga => | strigae +striola => | striolae +strobila => | strobilae +struma => | strumae +stryddag => | stryddae +succinea => succineas | succineae +summa => | summae +supernova => supernovas | supernovae +suprascapula => | suprascapulae +synaesthesia => | synaesthesiae +synapticula => synapticulas | +synechia => | synechiae +synesthesia => | synesthesiae +synusia => | synusiae +tabella => | tabellae +tabula => | tabulae +taenia => taenias | taeniae +talea => | taleae +tegula => | tegulae +tenia => tenias | teniae +terebratula => terebratulas | terebratulae +tessella => tessellas | tessellae +tessera => | tesserae +theca => | thecae +tibia => | tibiae +tipula => | tipulae +torula => | torulae +trabea => | trabeae +trabecula => | trabeculae +trachea => | tracheae +trichina => trichine | trichinae +*umbra => umbras | umbrae +uncia => | unciae +usnea => usneas | usneae +utricularia => | utriculariae +uva => | uvae +vagina => vaginas | vaginae +vaginula => | vaginulae +vallecula => | valleculae +valvula => | valvulae +vena => | venae +verruca => | verrucae +vertebra => | vertebrae +vesicula => | vesiculae +virga => | virgae +vitta => | vittae +vomica => vomicas | vomicae +zoaea => | zoaeae +zoea => zoeas | zoeae +zooea => | zooeae + +# Latin imports ending in "-men" that classically inflect to "-mina"... + +foramen => foramens | foramina +gravamen => | gravamina +legumen => legumens | legumina +*lumen => lumens | lumina +molimen => | molimina +numen => | numina +representamen => representamens | representamina +stamen => stamen | stamina +tegmen => | tegmina +tentamen => | tentamina +velamen => | velamina + + +# Miscellaneous Latin imports that retain classical inflections... + +centumvir => | centumviri +corpus => corpuses | corpora +duumvir => duumvirs | duumviri +femur => femurs | femora +lemur => lemurs | lemures +septemvir => | septemviri +triumvir => triumvirs | triumviri + + +# Latin imports ending in "-um" that classically inflect to "-a"... + +abortorium => | abortoria +abstractum => | abstracta +addendum => addendums | addenda +adminiculum => | adminicula +adytum => | adyta +aecidium => | aecidia +agendum => | agenda +alluvium => alluviums | alluvia +ambulacrum => | ambulacra +amentum => | amenta +anthodium => | anthodia +antiserum => | antisera +antrum => | antra +apothecium => | apothecia +appressorium => | appressoria +apterium => | apteria +aquarium => aquariums | aquaria +arboretum => | arboreta +arcanum => | arcana +archegonium => | archegonia +arcosolium => | arcosolia +argumentum => | argumenta +ascidium => | ascidia +asylum => asylums | asyla +avicularium => | avicularia +axopodium => | axopodia +bacterium => | bacteria +bifolium => | bifolia +caecum => | caeca +calamistrum => | calamistra +candelabrum => | candelabra +castrum => | castra +cecidium => | cecidia +chromidium => | chromidia +claustrum => | claustra +cleithrum => | cleithra +clostridium => | clostridia +coagulum => | coagula +coccidium => | coccidia +collegium => | collegia +columbarium => | columbaria +compendium => compendiums | compendia +confluvium => | confluvia +conidium => | conidia +consortium => consortiums | consortia +contagium => | contagia +contrafactum => | contrafacta +corpusculum => | corpuscula +corrigendum => | corrigenda +cranium => craniums | crania +craspedum => | craspeda +cubiculum => | cubicula +curriculum => curriculums | curricula +cystidium => | cystidia +*datum => | data +decennium => | decennia +delirium => deliriums | deliria +denotatum => | denotata +dentalium => | dentalia +depositum => depositums | deposita +descriptum => | descripta +desideratum => | desiderata +designatum => | designata +dichasium => | dichasia +dictum => dictums | dicta +diverticulum => | diverticula +dolphinarium => dolphinariums | dolphinaria +emporium => emporiums | emporia +enconium => enconiums | enconia +epicardium => | epicardia +equinoctium => equinoctiums | equinoctia +equisetum => equisetums | equiseta +ergastulum => | ergastula +erratum => | errata +exemplum => | exempla +explanandum => | explananda +explicandum => | explicanda +extremum => extremums | extrema +faciendum => | facienda +flabellum => | flabella +flagellum => | flagella +forum => forums | fora +fraenum => | fraena +frustulum => | frustula +frustum => frustums | frusta +fulcrum => | fulcra +gametangium => | gametangia +germarium => | germaria +glochidium => | glochidia +gonangium => | gonangia +gonidium => | gonidia +gonimium => | gonimia +gubernaculum => | gubernacula +gymnasium => gymnasiums | gymnasia +halteridium => | halteridia +haustellum => | haustella +haustorium => | haustoria +haustrum => | haustra +hemelytrum => | hemelytra +honorarium => honorariums | honoraria +hordeolum => | hordeola +hormogonium => | hormogonia +hymenium => | hymenia +hymnarium => | hymnaria +hypnum => hypnums | hypna +idolum => | idola +ilium => | ilia +improperium => | improperia +indicium => | indicia +individuum => individuums | individua +indumentum => | indumenta +indusium => | indusia +inhalatorium => | inhalatoria +inoculum => | inocula +interambulacrum => | interambulacra +intermedium => | intermedia +internodium => | internodia +interregnum => interregnums | interregna +interstitium => interstitiums | interstitia +intervallum => intervallums | intervalla +involucrum => | involucra +ischium => | ischia +isidium => | isidia +judicatum => | judicata +jugum => | juga +labrum => | labra +leprosarium => | leprosaria +ligamentum => | ligamenta +lixivium => | lixivia +lomentum => | lomenta +lorum => | lora +lustrum => lustrums | lustra +manubrium => manubriums | manubria +mausoleum => mausoleums | mausolea +maximum => maximums | maxima +mediastinum => | mediastina +medium => mediums | media +megatherium => | megatheria +memorandum => memorandums | memoranda +mesothelium => | mesothelia +millennium => millenniums | millennia +minimum => minimums | minima +miracidium => | miracidia +mithraeum => | mithraea +momentum => momentums | momenta +monochasium => | monochasia +moratorium => moratoriums | moratoria +mortarium => | mortaria +municipium => | municipia +nemathecium => | nemathecia +nephridium => | nephridia +nodum => | noda +oceanarium => | oceanaria +odeum => | odea +olfactorium => | olfactoria +omentum => | omenta +ommatidium => | ommatidia +operculum => | opercula +optimum => optimums | optima +opusculum => | opuscula +osculum => | oscula +osmaterium => | osmateria +osmeterium => | osmeteria +ossiculum => | ossicula +ostium => | ostia +ovarium => | ovaria +ovulum => | ovula +ovum => | ova +pallium => | pallia +parapleurum => | parapleura +patagium => | patagia +pediluvium => | pediluvia +pendulum => pendulums | pendula +perceptum => | percepta +peridium => | peridia +perithecium => | perithecia +peronium => | peronia +phalangium => | phalangia +phylum => phylums | phyla +phyogemmarium => | phyogemmaria +pinetum => pinetums | pineta +pistillidium => | pistillidia +placitum => | placita +plasmodium => | plasmodia +plasmolyticum => | plasmolytica +plectrum => | plectra +plenarium => | plenaria +pleurum => | pleura +poculum => | pocula +podetium => | podetia +podium => podiums | podia +pollinarium => | pollinaria +pollinium => | pollinia +polythecium => | polythecia +portiforium => | portiforia +postulatum => | postulata +praecognitum => | praecognita +precognitum => | precognita +primordium => | primordia +principium => | principia +profluvium => | profluvia +progymnasium => | progymnasia +prolabium => | prolabia +propodium => | propodia +proprium => | propria +propylaeum => | propylaea +proscenium => | proscenia +prosopium => | prosopia +prothallium => | prothallia +pseudopodium => | pseudopodia +psydracium => | psydracia +pulmonarium => | pulmonaria +pulsellum => | pulsella +punctum => | puncta +pycnidium => | pycnidia +pycnium => | pycnia +pyxidium => | pyxidia +quaesitum => | quaesita +quantum => quantums | quanta +quinquennium => | quinquennia +referendum => referendums | referenda +refugium => | refugia +relatum => | relata +replum => | repla +residuum => residuums | residua +responsum => | responsa +retinaculum => | retinacula +rhopalium => | rhopalia +rhynchodaeum => | rhynchodaea +rostrum => rostrums | rostra +sacellum => | sacella +sacrarium => | sacraria +sacrum => sacrums | sacra +sagum => | saga +salivarium => | salivaria +sanatorium => sanatoriums | sanatoria +schistosomulum => | schistosomula +scholium => | scholia +scolopidium => | scolopidia +scriptorium => scriptoriums | scriptoria +scutellum => | scutella +scutulum => | scutula +scutum => | scuta +seaquarium => | seaquaria +secretum => | secreta +seminium => | seminia +sensedatum => | sensedata +sensillum => | sensilla +sensoriolum => | sensoriola +sensum => | sensa +septarium => | septaria +septum => | septa +sequestrum => | sequestra +sericterium => | sericteria +serum => serums | sera +sestertium => | sestertia +signum => | signa +simpulum => | simpula +simulacrum => simulacrums | simulacra +sistrum => sistrums | sistra +solarium => | solaria +solenium => | solenia +solstitium => | solstitia +soralium => | soralia +soredium => | soredia +spectrum => spectrums | spectra +speculum => speculums | specula +spermarium => | spermaria +spermatium => | spermatia +spermogonium => | spermogonia +sphagnum => sphagnums | sphagna +spiculum => | spicula +spiraculum => | spiracula +spirillum => | spirilla +sporodochium => | sporodochia +sputum => | sputa +stabilimentum => | stabilimenta +stadium => stadiums | stadia +staminidium => | staminidia +sternum => sternums | sterna +stichidium => | stichidia +stillicidium => | stillicidia +stomatium => | stomatia +*stratum => stratums | strata +striatum => | striata +stylopodium => | stylopodia +subsellium => | subsellia +subsidium => | subsidia +substratum => substratums | substrata +suggestum => suggestums | suggesta +supercilium => | supercilia +superstratum => | superstrata +suppositum => | supposita +supracleithrum => | supracleithra +sustentaculum => | sustentacula +syllabarium => | syllabaria +sympodium => | sympodia +symposium => symposiums | symposia +synangium => | synangia +synapticulum => | synapticula +synaxarium => | synaxaria +syncytium => | syncytia +syndendrium => | syndendria +synedrium => | synedria +tablinum => | tablina +tegmentum => | tegmenta +telium => | telia +tenaculum => | tenacula +tentaculum => | tentacula +tepidarium => | tepidaria +terebellum => | terebella +tergum => | terga +terrarium => terrariums | terraria +territorium => | territoria +tetrasporangium => | tetrasporangia +thanatorium => | thanatoria +thelycum => | thelyca +thyridium => | thyridia +tintinnabulum => | tintinnabula +tomium => | tomia +toxicum => | toxica +tractellum => | tractella +trapezium => trapeziums | trapezia +trichidium => | trichidia +triclinium => | triclinia +triforium => | triforia +triplum => | tripla +tropaeolum => tropaeolums | tropaeola +tuberculum => | tubercula +tympanum => | tympana +ultimatum => ultimatums | ultimata +uredinium => | uredinia +uredium => | uredia +urodaeum => | urodaea +urodeum => | urodea +vacuum => vacuums | vacua +vasculum => vasculums | vascula +vehiculum => | vehicula +velarium => | velaria +velum => velums | vela +vestigium => | vestigia +viaticum => | viatica +vibraculum => | vibracula +vinculum => | vincula +vitellarium => | vitellaria +vivarium => vivariums | vivaria +vomitorium => vomitoriums | vomitoria +zoarium => | zoaria +zooecium => | zooecia +zoosporangium => | zoosporangia +zygantrum => | zygantra + +# Latin imports ending in "-us" that classically inflect to "-i" + +acarus => | acari +acinus => | acini +aculeus => | aculei +alumnus => | alumni +alveolus => | alveoli +aptychus => | aptychi +aureus => | aurei +*bacillus => | bacilli +bronchus => | bronchi +bulimus => | bulimi +cactus => cactuses | cacti +caduceus => | caducei +calathus => | calathi +canaliculus => | canaliculi +cantharus => | canthari +cardophagus => | cardophagi +cercus => | cerci +cistophorus => | cistophorori +cladus => | cladi +conductus => | conducti +congius => | congii +convolvulus => convolvuluses | convolvuli +cultellus => | cultelli +cumulus => | cumuli +cuniculus => | cuniculi +cyathus => | cyathi +cynocephalus => | cynocephali +cysticercus => | cysticerci +denarius => | denarii +diplococcus => | diplococci +entrochus => | entrochi +eucalyptus => eucalyptuses | eucalypti +exencephalus => | exencephali +famulus => | famuli +fasciculus => | fasciculi +faveolus => | faveoli +flocculus => | flocculi +floccus => | flocci +focus => focuses | foci +fucus => | fuci +funambulus => | funambuli +fungus => funguses | fungi +gastrocnemius => | gastrocnemii +gladiolus => gladioluses | gladioli +guttus => | gutti +gymnotus => | gymnoti +gyrus => | gyri +hamulus => | hamuli +hippocampus => | hippocampi +hippopotamus => hippopotamuses | hippopotami +humerus => | humeri +ichthyosaurus => | ichthyosauri +incubus => incubuses | incubi +interradius => | interradii +isthmus => isthmuses | isthmi +lactobacillus => | lactobacilli +lemniscus => | lemnisci +lentiscus => | lentisci +limulus => | limuli +lithodomus => | lithodomi +lobulus => | lobuli +lochus => | lochi +loculus => | loculi +locus => | loci +lumbricus => | lumbrici +macacus => | macaci +magilus => | magili +magus => | magi +malleolus => | malleoli +malleus => | mallei +megalosaurus => | megalosauri +meniscus => | menisci +metatarsus => | metatarsi +microcephalus => | microcephali +micrococcus => | micrococci +micronucleus => | micronuclei +modernus => | moderni +modius => | modii +modulus => moduluses | moduli +modus => moduses | modi +nasutus => | nasuti +nauplius => | nauplii +nautilus => nautiluses | nautili +nidus => niduses | nidi +nimbus => nimbuses | nimbi +nodus => | nodi +nucleolus => nucleoluses | nucleoli +*nucleus => | nuclei +nucleus => nucleuses | nuclei +nuntius => | nuntii +obelus => | obeli +obolus => | oboli +ocellus => | ocelli +oculus => | oculi +ophiophagus => | ophiophagi +palpus => | palpi +palus => | pali +papyrus => papyruses | papyri +parabolanus => | parabolani +paranucleus => | paranuclei +penicillus => | penicilli +perradius => | perradii +phallus => phalluses | phalli +pileus => | pilei +pilus => | pili +plesiosaurus => | plesiosauri +pluteus => | plutei +postnatus => | postnati +prodromus => | prodromi +propositus => | propositi +protarsus => | protarsi +prothallus => | prothalli +protococcus => | protococci +pteropus => | pteropi +pullus => | pulli +pyrophorus => | pyrophori +quinarius => | quinarii +radius => radiuses | radii +ramulus => | ramuli +ramus => | rami +ranunculus => ranunculuses | ranunculi +rectus => | recti +regulus => | reguli +rhomboideus => | rhomboidei +rhythmus => | rhythmi +sacculus => | sacculi +sarcophagus => | sarcophagi +scalenus => | scaleni +scapus => | scapi +scarabaeus => | scarabaei +scarus => | scari +sciolus => | scioli +scyphus => | scyphi +senarius => | senarii +septenarius => | septenarii +silenus => | sileni +Silurus => | Siluri +siphunculus => | siphunculi +sipunculus => | sipunculi +solvus => | solvi +sorus => | sori +sparus => | spari +spasmus => | spasmi +spondylus => | spondyli +squalus => | squali +staphylococcus => | staphylococci +stimulus => | stimuli +strategus => | strategi +streptococcus => | streptococci +strobilus => | strobili +stylus => styluses | styli +succubus => succubuses | succubi +succus => | succi +sulcus => | sulci +surculus => | surculi +syllabus => syllabuses | syllabi +syncellus => | syncelli +synthronus => | synthroni +syrphus => | syrphi +talus => | tali +tarsus => | tarsi +terminus => terminuses | termini +thalamus => | thalami +thaumaturgus => | thaumaturgi +thesaurus => thesauruses | thesauri +tholus => | tholi +thymus => | thymi +thyrsus => | thyrsi +tornus => | torni +torulus => | toruli +torus => toruses | tori +toxius => | toxii +tragus => | tragi +trapezius => | trapezii +triradius => | triradii +trochus => trochuses | trochi +tubulus => | tubuli +tumulus => | tumuli +umbilicus => umbilicuses | umbilici +uncinus => | uncini +uncus => | unci +uraeus => | uraei +uredosorus => | uredosori +urus => uruses | uri +uterus => uteruses | uteri +vagus => | vagi +vermiculus => | vermiculi +versiculus => | versiculi +verticillus => | verticilli +villus => | villi +xiphopagus => | xiphopagi +xystus => | xysti +zoophorus => | zoophori +zophorus => | zophori + + +# Latin imports ending in "-is" that classically inflect to "-es"... + +axis => | axes +caulis => | caules +didymis => | didymes +follis => | folles +interaxis => | interaxes +pelvis => pelvises | pelves +penis => penises | penes +phototaxis => | phototaxes +postpubis => | postpubes +proavis => | proaves +synaxis => | synaxes +syntaxis => | syntaxes +syrtis => | syrtes +taxis => | taxes +tenuis => | tenues +testis => | testes +unguis => | ungues + + +# Latin imports ending in "-us" that classically don't inflect... + +apparatus => apparatuses | apparatus +cantus => cantuses | cantus +coitus => coituses | coitus +hiatus => hiatuses | hiatus +ignoramus => ignoramuses | ignoramus +impetus => impetuses | impetus +jacobus => jacobuses | jacobus +meatus => meatuses | meatus +nexus => nexuses | nexus +plexus => plexuses | plexus +prospectus => prospectuses | prospectus +sinus => sinuses | sinus +status => statuses | status +virus => viruses | +# Not correct, but occasionally (mis)used +virus => | viri +# Even less defensible, and widely (mis)used +virus => | virii + + +# Greek imports ending in "-on" that classically inflect to "-a"... + +anacoluthon => anacoluthons | anacolutha +anthemion => | anthemia +aphelion => | aphelia +asyndeton => | asyndeta +craspedon => | craspeda +criterion => | criteria +enteron => | entera +epilimnion => | epilimnia +epimeron => | epimera +epiphenomenon => | epiphenomena +epyllion => | epyllia +euporiston => | euporista +ganglion => ganglions | ganglia +hapteron => | haptera +*hedron => hedrons | hedra +*helion => helions | helia +hydraulicon => | hydraulica +hyperbaton => | hyperbata +hypolimnion => | hypolimnia +idolon => | idola +interphenomenon => | interphenomena +*legomenon => | legomena +lepton => | lepta +lithophyton => | lithophyta +logion => | logia +metalimnion => | metalimnia +metapleuron => | metapleura +microbion => | microbia +mitochondrion => | mitochondria +mixolimnion => | mixolimnia +monimolimnion => | monimolimnia +monosyllabon => | monosyllaba +monoxylon => | monoxyla +noumenon => | noumena +octohedron => octohedrons | octohedra +organon => | organa +oxybaphon => | oxybapha +oxymoron => oxymorons | oxymora +paraganglion => | paraganglia +parergon => | parerga +parhelion => parhelions | parhelia +parison => | parisa +pedion => | pedia +perikaryon => | perikarya +*phenomenon => | phenomena +pleuron => | pleura +podion => | podia +porion => | poria +prokaryon => | prokarya +prolegomenon => | prolegomena +propleuron => | propleura +propylon => propylons | propyla +prosencephalon => | prosencephala +prosodiencephalon => | prosodiencephala +prototypon => prototypons | prototypa +protypon => | protypa +pyramidion => pyramidions | pyramidia +rhododendron => rhododendrons | rhododendra +rhombohedron => rhombohedrons | rhombohedra +spermatoon => | spermatoa +stasimon => stasimons | stasima +stephanion => stephanions | stephania +stomion => | stomia +synaxarion => | synaxaria +synedrion => | synedria +taxon => | taxa +tetracolon => | tetracola +tetragrammaton => | tetragrammata +tetrahedron => tetrahedrons | tetrahedra +tetrapleuron => tetrapleurons | tetrapleura +theologoumenon => | theologoumena +thymiaterion => | thymiateria +trapezohedron => trapezohedrons | trapezohedra +troparion => | troparia +xiphiplastron => | xiphiplastra +xiphoplastron => | xiphoplastra +xoanon => | xoana +zygon => | zyga + + +# Spanish imports that classically inflect as in Spanish... + +cargador => | cargadores +furfur => | furfures +parador => paradors | paradores +temblor => | temblores +carmen => carmens | carmina + + +# Italian imports that (mostly) inflect classically to "-i" + +albergo => | alberghi +allargando => | allargandi +amoretto => | amoretti +amorino => | amorini +ballabile => | ballabili +bozzetto => | bozzetti +carabiniere => | carabinieri +cassone => cassones | cassoni +castrato => | castrati +centesimo => | centesimi +chitarrone => | chitarroni +cognoscente => | cognoscenti +concetto => | concetti +condottiere => | condottieri +conoscente => | conoscenti +contadino => | contadini +conversazione => conversaziones | conversazioni +cornetto => | cornetti +corno => | corni +dilettante => dilettantes | dilettanti +evirato => | evirati +figurante => figurantes | figuranti +frate => | frati +graffito => | graffiti +grano => | grani +grissino => | grissini +improvisatrice => | improvisatrici +libretto => librettos | libretti +mafioso => | mafiosi +modelletto => | modelletti +mondo => | mondi +moroso => | morosi +moscardino => | moscardini +motoscafo => | motoscafi +ovolo => | ovoli +paparrazo => | paparrazi +pastorale => pastorales | pastorali +pensiero => | pensieri +pifferaro => | pifferari +podere => | poderi +porcino => | porcini +putto => | putti +ragazzo => | ragazzi +ricordo => | ricordi +rione => | rioni +saffo => | saffi +sbirro => | sbirri +scudo => | scudi +scungille => | scungilli +sestiere => | sestieri +sgraffiato => | sgraffiati +soldo => | soldi +stornello => | stornelli +strambotto => | strambotti +tarantato => | tarantati +tempietto => | tempietti +tenorino => | tenorini +terzetto => | terzetti +tombarolo => | tombaroli +tondo => | tondi +Tornese => | Tornesi +trullo => | trulli +uomo => | uomini +vetturino => | vetturini +viale => | viali +villino => | villini +volcanello => | volcanelli +zeppole => | zeppoli +zingano => | zingani + + +# Italian imports ending in "-a" that classically inflect to "-e" + +ancona => | ancone +autostrada => autostradas | autostrade +ballata => | ballate +ballerina => ballerinas | ballerine +bruschetta => | bruschette +canzonetta => canzonettas | canzonette +contadina => | contadine +crazia => | crazie +fermata => fermatas | fermate +fioritura => | fioriture +frottola => | frottole +granita => | granite +loggia => loggias | loggie +mafiosa => | mafiose +mantelletta => | mantellette +maremma => | maremme +mortadella => mortadellas | mortadelle +paisa => paisas | paise +pietra => | pietre +pizza => pizzas | pizze +ragazza => | ragazze +ricercata => | ricercate +scuola => | scuole +squadra => | squadre +tarantata => | tarantate +tazza => | tazze +terramara => | terremare +trattoria => trattorias | trattorie +vila => vilas | vile +villanella => | villanelle +violetta => | violette +zadruga => zadrugas | zadruge +zitella => | zitelle +zucca => | zucche +zuppa => | zuppe + + +# Italian imports that retain their classical inflection to "-i" + +alto => altos | alti +basso => bassos | bassi +biscotto => | biscotti +contralto => contraltos | contralti +glissando => glissandos | glissandi +panino => | panini +piano => pianos | piani +solo => solos | soli +soprano => sopranos | soprani +tempo => tempos | tempi +vaporetto => vaporettos | vaporetti +virtuoso => virtuosos | virtuosi + + +# Words ending in '-oe' which are ambiguous in the plural... + +coe => coes +hoe => hoes +joe => joes +moe => moes +toe => toes + +# Italian and Spanish imports, abbreviations, and other words ending in "-o" +# that always inflect to "-os" + +ado => ados +aficionado => aficionados +aggro => aggros +albino => albinos +allegro => allegros +altorelievo => altorelievos +ammo => ammos +Antananarivo => Antananarivos +armadillo => armadillos +auto => autos +aviso => avisos +avocado => avocados +Bamako => Bamakos +Barquisimeto => Barquisimetos +bimbo => bimbos +bingo => bingos +Biro => Biros +bolero => boleros +Bolzano => Bolzanos +Boto => Botos +burro => burros +Cairo => Cairos +calypso => calypsos +canto => cantos +cappuccino => cappuccinos +casino => casinos +cello => cellos +Chicago => Chicagos +Chimango => Chimangos +cilantro => cilantros +cochito => cochitos +coco => cocos +Colombo => Colombos +Colorado => Colorados +commando => commandos +concertino => concertinos +condo => condos +contango => contangos +credo => credos +crescendo => crescendos +cyano => cyanos +demo => demos +ditto => dittos +Draco => Dracos +dynamo => dynamos +embryo => embryos +Esperanto => Esperantos +espresso => espressos +euro => euros +falsetto => falsettos +Faro => Faros +fiasco => fiascos +Filipino => Filipinos +flamenco => flamencos +furioso => furiosos +generalissimo => generalissimos +Gestapo => Gestapos +ghetto => ghettos +gigolo => gigolos +gizmo => gizmos +Greensboro => Greensboros +gringo => gringos +Guaiabero => Guaiaberos +guano => guanos +gumbo => gumbos +gyro => gyros +hairdo => hairdos +hippo => hippos +Idaho => Idahos +impetigo => impetigos +inferno => infernos +info => infos +intaglio => intaglios +intermezzo => intermezzos +intertrigo => intertrigos +Iquico => Iquicos +jalapeno => jalapenos +jumbo => jumbos +junto => juntos +Kakapo => Kakapos +kilo => kilos +kimono => kimonos +Kinkimavo => Kinkimavos +Kokako => Kokakos +Kosovo => Kosovos +Lesotho => Lesothos +libero => liberos +libido => libidos +lido => lidos +Lilo => Lilos +limbo => limbos +limo => limos +lineno => linenos +lingo => lingos +lino => linos +livedo => livedos +loco => locos +logo => logos +lumbago => lumbagos +macho => machos +macro => macros +mafioso => mafiosos +magneto => magnetos +magnifico => magnificos +Majuro => Majuros +Malabo => Malabos +manifesto => manifestos +Maputo => Maputos +Maracaibo => Maracaibos +memo => memos +metro => metros +Mexico => Mexicos +micro => micros +Milano => Milanos +Monaco => Monacos +mono => monos +Montenegro => Montenegros +Morocco => Moroccos +Muqdisho => Muqdishos +mustachio => mustachios +myo => myos +neutrino => neutrinos +Ningbo => Ningbos +octavo => octavos +oregano => oreganos +Orinoco => Orinocos +Orlando => Orlandos +Oslo => Oslos +oto => otos +panto => pantos +Paramaribo => Paramaribos +Pardusco => Parduscos +pedalo => pedalos +photo => photos +pimento => pimentos +pinto => pintos +pleco => plecos +Pluto => Plutos +pogo => pogos +polo => polos +poncho => ponchos +Porto => Portos +Porto-Novo => Porto-Novos +pro => pros +psycho => psychos +pueblo => pueblos +quarto => quartos +Quito => Quitos +rhino => rhinos +rilievo => rilievos +risotto => risottos +rococo => rococos +rondo => rondos +Sacramento => Sacramentos +saddo => saddos +sago => sagos +salvo => salvos +Santiago => Santiagos +Sapporo => Sapporos +Sarajevo => Sarajevos +scherzando => scherzandos +scherzo => scherzos +silo => silos +sirocco => siroccos +sombrero => sombreros +staccato => staccatos +sterno => sternos +stucco => stuccos +stylo => stylos +sumo => sumos +surimono => surimonos +Taiko => Taikos +techno => technos +terrazzo => terrazzos +testudo => testudos +timpano => timpanos +tiro => tiros +tobacco => tobaccos +Togo => Togos +Tokyo => Tokyos +torero => toreros +Torino => Torinos +Toronto => Torontos +torso => torsos +tremolo => tremolos +typo => typos +tyro => tyros +vaquero => vaqueros +vermicello => vermicellos +verso => versos +vibrato => vibratos +violoncello => violoncellos +Virgo => Virgos +weirdo => weirdos +Yamoussoukro => Yamoussoukros +yo-yo => yo-yos +zero => zeros +Zibo => Zibos + + +# Words ending in "-o" that may inflect to "-os" or "-oes"... + +adviso => | advisoes +ambuscado => ambuscados | ambuscadoes +arango => | arangoes +archipelago => archipelagos | archipelagoes +barrico => | barricoes +bilbo => | bilboes +bongo => bongos | bongoes +bravo => bravos | bravoes +bubo => | buboes +busto => bustos | bustoes +go => | goes +grotto => grottos | grottoes +guglio => guglios | guglioes +hero => | heroes +mango => mangos | mangoes +medico => medicos | medicoes +memento => mementos | mementoes +motto => mottos | mottoes +pengo => pengo | pengoes +pingo => pingos | pingoes +placebo => placebos | placeboes +po => pos | poes +politico => politicos | politicoes +portico => porticos | porticoes +potato => | potatoes +proviso => provisos | provisoes +sambo => sambos | samboes +stiletto => | stilettoes +tango => tangos | tangoes +tomato => | tomatoes +volcano => volcanos | volcanoes +waldo => waldos | waldoes + + +# Words ending in "-ch" that inflect to "-chs" (instead of "-ches")... + +bath => baths +Czech => Czechs +eunuch => eunuchs +math => maths +mouth => mouths +oath => oaths +path => paths +stomach => stomachs +wreath => wreaths + + +# Greek imports (via Latin or Spanish) ending in "-o(n)" that classically inflect to "-nes"... + +agon => | agones +ambo => ambos | ambones +autochthon => autochthons | autochthones +axon => axons | axones +bodegon => | bodegones +cardo => | cardines +felo => | felones +imago => imagos | imagines +lentigo => | lentigines +mucro => mucros | mucrones +Pangasinan => Pangasinans | Pangasinanes +pernio => | perniones +phren => | phrenes +porron => porrons | porrones +reductio => | reductiones +rejon => | rejones +serpigo => serpigoes | serpigines +somaten => | somatenes +stolo => | stolones +telamon => | telamones +teredo => teredos | teredines +thraso => thrasoes | thrasones +turron => turrons | turrones +umbo => umbos | umbones +unio => unios | uniones +ustilago => | ustilagines +vibrio => vibrios | vibriones + + +# Greek imports (via Latin) ending in "-x" that classically inflect to "-ges"... + +phalanx => phalanxes | phalanges +remex => remexes | remiges +larynx => | larynges +sphinx => sphinxes | sphinges + + +# Latin or Greek imports ending in "-x" that classically inflect to "-ces"... + +apex => apexes | apices +appendix => appendixes | appendices +auspex => | auspices +calix => | calices +carex => | carices +caudex => | caudices +cicatrix => | cicatrices +cimex => | cimices +codex => | codices +cortex => cortexes | cortices +coxendix => | coxendices +directrix => | directrices +extispex => | extispices +falx => | falces +hallux => | halluces +haruspex => | haruspices +*helix => | helices +imbrex => | imbrices +index => indexes | indices +latex => latexes | latices +limax => | limaces +mediatrix => | mediatrices +meretrix => | meretrices +murex => murexes | murices +nectocalyx => | nectocalyces +oratrix => | oratrices +pinax => | pinaces +pneumothorax => pneumothoraxes | pneumothoraces +pollex => | pollices +pontifex => pontifexes | pontifices +prosecutrix => | prosecutrices +pulveratrix => | pulveratrices +quadratrix => | quadratrices +radix => radixes | radices +scolex => | scoleces +separatrix => | separatrices +silex => | silices +simplex => simplexes | simplices +spadix => spadixes | spadices +streptothrix => | streptothrices +suffrutex => | suffrutices +thorax => thoraxes | thoraces +tortrix => | tortrices +tractatrix => | tractatrices +tractrix => | tractrices +varix => | varices +vertex => vertexes | vertices +vibex => | vibices +vortex => vortexes | vortices + + + +# Arabic imports ending in "-t" that classically inflect to "-ti"... + +afrit => afrits | afriti +afreet => afreets | afreeti +efreet => efreets | efreeti + + +# Hebrew imports that classically inflect by adding "-im"... + +Asherah => Asherahs | Asherim +baal => baals | baalim +cherub => cherubs | cherubim +gaon => gaons | gaonim +goy => goys | goyim +kibbutz => kibbutzes | kibbutzim +meshumad => | meshumadim +meshummad => | meshummadim +minyan => | minyanim +parnas => | parnassim +parnass => | parnassim +seraph => seraphs | seraphim +shochet => | shochetim +ulpan => | ulpanim +zuz => zuzzes | zuzim + + +# Pairs or groups subsumed to a singular that don't inflect... + +britches => britches +clippers => clippers +gallows => gallows +headquarters => headquarters +herpes => herpes +hijinks => hijinks +innings => innings +offspring => offspring +pajamas => pajamas +pants => pants +pincers => pincers +pliers => pliers +proceedings => proceedings +pyjamas => pyjamas +scissors => scissors +shears => shears +shorts => shorts +testes => testes +tongs => tongs +trousers => trousers + + +# Inuktitut imports ending in "-uk" that always inflect to "-uit"... + +inuk => inuit +inukshuk => inukshuit + + +# French imports ending in "-u" that classically inflect to "-ux"... + +aboiteau => aboiteaus | aboiteaux +bandeau => | bandeaux +bateau => | bateaux +beau => beaus | beaux +bijou => | bijoux +bordereau => | bordereaux +bureau => bureaus | bureaux +chapeau => | chapeaux +chateau => | chateaux +cheval => | chevaux +chou => | choux +fabliau => | fabliaux +fricandeau => | fricandeaux +jeu => | jeux +maquereau => | maquereaux +morceau => | morceaux +plateau => plateaus | plateaux +portmanteau => portmanteaus | portmanteaux +tableau => tableaus | tableaux +tonneau => tonneaus | tonneaux +trousseau => trousseaus | trousseaux +trumeau => | trumeaux +voeu => | voeux + + +# (Mainly) French or Latin imports ending in "-s" that (mostly) don't inflect... + +chassis => | chassis +contretemps => | contretemps +corps => | corps +debris => | debris +glacis => glacises | glacis +haggis => | haggis +louis => | louis +planctus => | planctus +precis => | precis +sedes => | sedes +superficies => | superficies + + +# French imports ending in "-u" that inflect to "-us" + +menu => menus +parvenu => parvenus + + +# French imports ending in "-ieu" that inflect to "-ieus" or "-ieux" + +adieu => adieus | adieux +lieu => lieus | lieux +milieu => milieus | milieux +purlieu => purlieus | purlieux + + +# French imports ending in "-eau" that inflect to "-eaus" or "-eaux" + +bandeau => bandeaus | bandeaux +bateau => bateaus | bateaux +beau => beaus | beaux +bureau => bureaus | bureaux +chapeau => chapeaus | chapeaux +chateau => chateaus | chateaux +jambeau => jambeaus | jambeaux +manteau => manteaus | manteaux +plateau => plateaus | plateaux +politbureau => politbureaus | politbureaux +portmanteau => portmanteaus | portmanteaux +rideau => rideaus | rideaux +rondeau => rondeaus | rondeaux +tableau => tableaus | tableaux +tonneau => tonneaus | tonneaux +trousseau => trousseaus | trousseaux + +# Names of diseases that don't inflect... + +diabetes => diabetes +*measles => measles +mumps => mumps +*pox => pox +rabies => rabies + + +# Miscellaneous words ending with "-s" that don't inflect... + +corps => corps +jackanapes => jackanapes +leptomonas => leptomonas +news => news +res => res +schizostylis => schizostylis +series => series +species => species + + +# Herd/cluster lifeforms that classically don't inflect... + +*bass => basses | bass +bison => bisons | bison +bream => | bream +buffalo => buffalos | buffalo +caribou => caribous | caribou +carp => | carp +cod => | cod +dace => daces | dace +*deer => | deer +eland => elands | eland +elk => elks | elk +*fish => | fish +flounder => | flounder +*fowl => fowls | fowl +grouse => grouses | grouse +haddock => haddocks | haddock +hake => hakes | hake +halibut => halibuts | halibut +herring => herrings | herring +mackerel => mackerels | mackerel +moose => | moose +pickerel => pickerels | pickerel +pike => pikes | pike +rhinoceros => rhinoceroses | rhinoceros +roe => roes | roe +salmon => | salmon +seed => seeds | seed +shad => shads | shad +*sheep => | sheep +snipe => snipes | snipe +starfish => starfishes | starfish +swine => swine | swines +teal => teals | teal +trout => | trout +tuna => | tuna +turbot => turbots | turbot +whiting => | whiting +*wildebeest => wildebeests | wildebeest +zucchini => zucchinis | zucchini + + +# Vehicles that don't inflect... + +*craft => craft + +# Other imports that don't inflect... + +intichiuma => intichiuma +paha => paha +ri => ri +samurai => samurai +soshi => soshi + + +# Individuals of nationalities end in "-ese" that don't inflect... + +Achinese => Achinese +Alfurese => Alfurese +Amboinese => Amboinese +Americanese => Americanese +Amoyese => Amoyese +Amoyese => Amoyese +Andamanese => Andamanese +Angolese => Angolese +Annamese => Annamese +Aragonese => Aragonese +Arakanese => Arakanese +Assamese => Assamese +Avignonese => Avignonese +Azerbaijanese => Azerbaijanese +Balinese => Balinese +Bengalese => Bengalese +Bernese => Bernese +Bhutanese => Bhutanese +Bolognese => Bolognese +Borghese => Borghese +Borghese => Borghese +Bostonese => Bostonese +Buginese => Buginese +Burmese => Burmese +Calabrese => Calabrese +Camaldolese => Camaldolese +Cantonese => Cantonese +Carlylese => Carlylese +Cassinese => Cassinese +Celanese => Celanese +Ceylonese => Ceylonese +Chinese => Chinese +Congoese => Congoese +Congoese => Congoese +Congolese => Congolese +Dongolese => Dongolese +Faroese => Faroese +Faroese => Faroese +Ferrarese => Ferrarese +Foochowese => Foochowese +Foochowese => Foochowese +Gabunese => Gabunese +Genevese => Genevese +Genevese => Genevese +Genoese => Genoese +Genoese => Genoese +Gilbertese => Gilbertese +Gilbertese => Gilbertese +Goanese => Goanese +Guianese => Guianese +Hainanese => Hainanese +Hararese => Hararese +Harlemese => Harlemese +Havanese => Havanese +Heavenese => Heavenese +Hoosierese => Hoosierese +Hottentotese => Hottentotese +Hottentotese => Hottentotese +Hunanese => Hunanese +Indochinese => Indochinese +Japanese => Japanese +Javanese => Javanese +Johnsonese => Johnsonese +Kanarese => Kanarese +Kiplingese => Kiplingese +Kiplingese => Kiplingese +Kongoese => Kongoese +Kongoese => Kongoese +Kongolese => Kongolese +Lapponese => Lapponese +Lebanese => Lebanese +Leonese => Leonese +Londonese => Londonese +Lorrainese => Lorrainese +Lucchese => Lucchese +Lucchese => Lucchese +Lyonese => Lyonese +Macanese => Macanese +Macassarese => Macassarese +Madurese => Madurese +Malabarese => Malabarese +Maltese => Maltese +Maltese => Maltese +Messinese => Messinese +Milanese => Milanese +Modenese => Modenese +Muranese => Muranese +Nankingese => Nankingese +Nankingese => Nankingese +Navarrese => Navarrese +Nepalese => Nepalese +Niasese => Niasese +Niasese => Niasese +Nicobarese => Nicobarese +Nipponese => Nipponese +Parmese => Parmese +Pekingese => Pekingese +Pekingese => Pekingese +Piedmontese => Piedmontese +Piedmontese => Piedmontese +Pistoiese => Pistoiese +Pistoiese => Pistoiese +Polonese => Polonese +Portuguese => Portuguese +Portuguese => Portuguese +Romagnese => Romagnese +Romanese => Romanese +Sangirese => Sangirese +Sarawakese => Sarawakese +Sarawakese => Sarawakese +Senegalese => Senegalese +Shavese => Shavese +Shavese => Shavese +Shawanese => Shawanese +Siamese => Siamese +Sienese => Sienese +Sikkimese => Sikkimese +Singhalese => Singhalese +Sinhalese => Sinhalese +Sogdianese => Sogdianese +Sudanese => Sudanese +Sundanese => Sundanese +Swahilese => Swahilese +Tenggerese => Tenggerese +Timorese => Timorese +Tirolese => Tirolese +Tocharese => Tocharese +Tonkinese => Tonkinese +Torinese => Torinese +Tyrolese => Tyrolese +Vermontese => Vermontese +Vermontese => Vermontese +Veronese => Veronese +Viennese => Viennese +Vietnamese => Vietnamese +Wenchowese => Wenchowese +Wenchowese => Wenchowese +Whitmanese => Whitmanese +Yengeese => Yengeese +Yunnanese => Yunnanese + + +# Singular words (mainly Latin and Greek imports) ending in "-s" that inflect to "-ses" (instead of "-sses")... + +abacus => abacuses +abortus => abortuses +acropolis => acropolises +aegis => aegises +alias => aliases +asbestos => asbestoses +bathos => bathoses +bias => biases +bolus => boluses +bronchitis => bronchitises +bursitis => bursitises +caddis => caddises +callus => calluses +cannabis => cannabises +canvas => canvases +chaos => chaoses +chorus => choruses +cosmos => cosmoses +dais => daises +digitalis => digitalises +epidermis => epidermises +ethos => ethoses +eyas => eyases +flatus => flatuses +gas => gases +glottis => glottises +hubris => hubrises +ibis => ibises +lens => lenses +linctus => linctuses +mantis => mantises +marquis => marquises +metropolis => metropolises +moaks => moakses +pathos => pathoses +polis => polises +sassafras => sassafrases +trellis => trellises + + +# Miscellaneous uncategorized imported words with native inflexions... +# (Some of these should probably be under earlier classifications. Patches welcome!) + +aelf => aelfe +agrogorod => agrogoroda +braccio => braccia +capataz => capataces +chapplis => chapplies +competent => competentes +cornu => cornua +crus => crura +denkmal => denkmaler +espanol => espanoles +ex => exes +felsenmeer => felsenmeere +gmina => gminy +gousblom => gousblomme +guy => guys +heft => hefte +hoti => hoties +hsien => heen +interleaf => leaves +interrex => interreges +juelet => iueles +kletterschuh => kletterschuhe +lied => lieder +macaroni => macaronies +matin => matins +mezuza => mezuzoth +mezuzah => mezuzoth +minnelied => minnelieder +nachtlokal => nachtlokale +nebenkern => nebenkerne +nockerl => nockerln +ogle => oglys +orthoceras => orthocerata +pectus => pectora +pillie => pilleis +poblador => pobladores +promerops => promeropes +puttony => puttonys +radiale => radialia +reich => reiche +rejoneador => rejoneadores +rete => retia +rezident => rezidenty +rype => ryper +sachverhalt => sachverhalte +sceat => sceattas +sedile => sedilia +seecatch => seecatchie +senex => senes +sezession => sezessionen +shomer => shomrim +snekkja => snekkjur +sol => soles +sphex => spheges +stirps => stirpes +thos => thoes +toril => toriles +tuber => tuberes +vas => vasa +vis => vires +voorbok => voorbokke +vorspiel => vorspiele +wanderjahr => wanderjahre +wandervogel => wandervogel +yuo => yuon +zeitgeber => zeitgebers + +# Miscellaneous (mostly imported) words with classical native inflections... +# (Some of these should probably be under earlier classifications. Patches welcome!) + +alguacil => alguacils | alguaciles +amphipneust => amphipneusts | amphipneusta +antefix => antifixes | antefixa +bechuana => bechuanas | bechuana +bhikshu => bhikshus | bhikshook +bierstube => bierstubes | bierstuben +bratwurst => bratwursts | bratwurste +bylina => bylinas | byliny +cabaletta => cabalettas | cabalette +corgi => corgis | corgwn +corgy => corgys | corgwn +cremaster => cremasters | cremasteres +cyclops => cyclopses | cyclopes +dreikanter => dreikanters | dreikanter +dumka => dumkas | dumky +feis => fess | feiseanna +fly => flies | flys +frenum => frena | fraena +galla => gallas | galla +geisha => geishas | geisha +intercalarium => intercalaria | intercalare +iter => iters | itinera +kar => kars | kare +karakia => karakias | karakia +karrenfeld => karrenfelds | karrenfelder +kioko => kiokos | kioko +lacunar => lacunars | lacunaria +lar => lars | lares +logodaedalus => logodaedali | logodaedale +maar => maars | maare +mukim => mukims | mukim +nenets => nentsi | nentsy +nymphaeum => nymphea | nymphaea +nympheum => nymphea | nymphaea +pangasinan => pangasinans | pangasinanes +pinon => pinons | pinones +pipkrake => pipkrakes | pipkraker +plethron => plethra | plether +prytanis => prytanes | prytan +purum => purums | purum +pyrites => pyritae | pirrites +raggare => raggares | raggare +regidor => regidors | regidores +remous => remous | remou +rimon => rimonim | rimmonim +salita => salitas | salite +sandr => sandrs | sandr +scazon => scazontes | scazons +sephardi => sephardim | sephardin +serir => serirs | serir +shauri => shauris | shauries +shawabti => shawabtis | shawabtiu +silbador => silbadors | silbadores +sinfonia => sinfonias | sinfonie +solidus => solidi | solidos +sotch => sotches | sotchs +souvlaki => souvlakis | souvlakia +sphaeridium => sphaeridia | sphaerideum +starover => starovers | starovery +stomodaeum => stomodea | stomodaea +stromodeum => stromodea | stromodaea +tetanothrum => tetanothra | tetanother +tsuba => tsubas | tsuba +tsubo => tsubos | tsubo +vaalpens => vaalpens | vaalpensen +varella => varellaes | varely +veduta => vedutas | vedute +wadi => wadies | wadis +wady => wadies | wadys +zemirah => zemiroth | zemirot +zita => ziti | zite + + +# "General" as a noun (as opposed to a postfix adjective)... + +adjutant general => adjutant generals +brigadier general => brigadier generals +lieutenant general => lieutenant generals +major general => major generals +-star general => -star generals + + +# Compound postfix forms require recursive inflection of the core noun(s)... +# ['(SING)-general' is non-indicative because it includes the above '-star general' form] + +(SING)-general => (PL)-general # E.g. Consul General --> Consuls General + +# E.g. son-of-a-gun --> sons-of-guns +son-of-a-(SING) => sons-of-(PL) +# E.g. mother-in-law --> mothers-in-law +(SING)-(PREP)-* => (PL)-(PREP)-* +# E.g. of him --> of them +(PREP)-(SING) => (PREP)-(PL) +# E.g. knight-errant --> knights-errant +(SING)-errant => (PL)-errant +# E.g. passer-by --> passers-by +(SING)-(PREP) => (PL)-(PREP) + +# Pronouns in the nominative... + +I => we +you => you +they => they +she => they +he => they +it => they +this => these +that => those +one => some + + +# Pronouns in the accusative... + +me => us +you => you +them => them +her => them +him => them + + +# Pronouns in the reflexive... + +myself => ourselves +yourself => yourselves +themself => themselves +herself => themselves +himself => themselves +itself => themselves + + +# Pronouns in the possessive... + +mine => ours +yours => yours +theirs => theirs +hers => theirs +his => theirs +its => theirs + + + +# Standard patterns of inflection for other nouns (in increasing order of generality)... + +-[aeiou]o => -[aeiou]os | +-[aeo]lf => | -[aeo]lves +-[aiy]nx => -[aiy]nxes | -[aiy]nges +-arf => | -arves +-ceps => -ceps | +-[cs]h => -[cs]hes | +-eaf => -eaves | +-eau => -eaus | -eaux +-ieu => -ieus | -ieux +-nife => -nives | +-oe => -oes | +-o => -oes | +-quy => -quies | +-[aeiou]y => -[aeiou]ys | +-ss => -sses | +-[^s]sis => | -[^s]ses +-trix => -trixes | -trices +-us => -uses | +-x => -xes | +-y => -ies | +-z => -zzes | +-zoon => | -zoa
\ No newline at end of file diff --git a/data/prepositions.txt b/data/prepositions.txt new file mode 100644 index 0000000..b7b5c65 --- /dev/null +++ b/data/prepositions.txt @@ -0,0 +1,51 @@ +aboard +behind +during +about +below +except +above +beneath +for +across +beside +from +after +besides +in +against +between +inside +along +beyond +into +among +but +like +around +by +near +at +concerning +of +before +down +off +on +throughout +until +out +till +up +over +to +upon +past +toward +with +since +under +within +through +underneath +without
\ No newline at end of file diff --git a/src/examples/java/bjc/inflexion/InflexionTester.java b/src/examples/java/bjc/inflexion/InflexionTester.java new file mode 100644 index 0000000..00ae3e2 --- /dev/null +++ b/src/examples/java/bjc/inflexion/InflexionTester.java @@ -0,0 +1,67 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion; + +import bjc.inflexion.v2.Noun; +import bjc.inflexion.v2.Nouns; +import bjc.inflexion.v2.Prepositions; + +import java.util.Scanner; + +/** + * Test inflecting words. + * + * @author EVE + * + */ +public class InflexionTester { + /** + * Main method. + * + * @param args + * Unused CLI args. + */ + public static void main(String[] args) { + Prepositions prepositionDB = new Prepositions(); + prepositionDB.loadFromStream(InflexionTester.class.getResourceAsStream("/prepositions.txt")); + + Nouns nounDB = new Nouns(); + nounDB.loadFromStream(InflexionTester.class.getResourceAsStream("/nouns.txt")); + + Scanner scn = new Scanner(System.in); + + System.out.print("Enter a noun to inflect (blank line to quit): "); + String ln = scn.nextLine().trim(); + + while(!ln.equals("")) { + System.out.println(); + + Noun noun = nounDB.getNoun(ln); + + if(noun == null) { + System.out.println("No inflection available for noun " + ln); + } else { + System.out.printf("Word: %s\nSingular: %s\nModern Plural: %s\tClassical Plural: %s\n\n", + ln, noun.singular(), noun.modernPlural(), noun.classicalPlural()); + } + + System.out.print("Enter a noun to inflect (blank line to quit: "); + ln = scn.nextLine().trim(); + } + + scn.close(); + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/CategoricalNounInflection.java b/src/main/java/bjc/inflexion/v2/CategoricalNounInflection.java new file mode 100644 index 0000000..597b2a3 --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/CategoricalNounInflection.java @@ -0,0 +1,204 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +/** + * Implementation of {@link NounInflection} for nouns matched by a regular + * expression. + * + * @author EVE + * + */ +public class CategoricalNounInflection implements NounInflection { + private static final String TOSTRING_FMT = "CategoricalNounInflection [singular=%s, modernPlural=%s," + + " classicalPlural=%s]"; + + private InflectionAffix singular; + + private InflectionAffix modernPlural; + private InflectionAffix classicalPlural; + + private boolean preferClassical; + + /** + * Create a new categorical inflection. + * + * @param singlar + * The affix for the singular form. + * @param modrnPlural + * The affix for the modern plural. + * @param classiclPlural + * The affix for the classical plural. + * @param prefrClassical + * Whether or not the classical plural should be + * preferred. + */ + public CategoricalNounInflection(InflectionAffix singlar, InflectionAffix modrnPlural, + InflectionAffix classiclPlural, boolean prefrClassical) { + if(singlar == null) + throw new NullPointerException("Singular form must not be null"); + else if(modrnPlural == null && classiclPlural == null) + throw new NullPointerException("One of modern/classical plural forms must not be null"); + + singular = singlar; + modernPlural = modrnPlural; + classicalPlural = classiclPlural; + preferClassical = prefrClassical; + } + + @Override + public boolean matches(String noun) { + if(singular.hasAffix(noun)) + return true; + else if(modernPlural != null && modernPlural.hasAffix(noun)) + return true; + else if(classicalPlural != null && classicalPlural.hasAffix(noun)) + return true; + else + return false; + } + + @Override + public boolean isSingular(String noun) { + if(singular.hasAffix(noun)) + return true; + else if(matchesPlural(noun)) + return false; + else { + String msg = String.format("Noun '%s' doesn't belong to this inflection", noun, this); + + throw new InflectionException(msg); + } + } + + @Override + public boolean isPlural(String noun) { + if(singular.hasAffix(noun)) + return false; + else if(matchesPlural(noun)) + return true; + else { + String msg = String.format("Noun '%s' doesn't belong to this inflection", noun, this); + + throw new InflectionException(msg); + } + } + + @Override + public String singularize(String plural) { + if(singular.hasAffix(plural)) + return plural; + else if(modernPlural != null && modernPlural.hasAffix(plural)) + return singular.affix(modernPlural.deaffix(plural)); + else if(classicalPlural != null && classicalPlural.hasAffix(plural)) + return singular.affix(classicalPlural.deaffix(plural)); + else { + String msg = String.format("Noun '%s' doesn't belong to this inflection", plural, this); + + throw new InflectionException(msg); + } + } + + @Override + public String pluralize(String singlar) { + if(singular.hasAffix(singlar)) { + if(preferClassical) { + if(classicalPlural == null) { + return modernPlural.affix(singular.deaffix(singlar)); + } else { + return classicalPlural.affix(singular.deaffix(singlar)); + } + } else { + if(modernPlural == null) { + return classicalPlural.affix(singular.deaffix(singlar)); + } else { + return modernPlural.affix(singular.deaffix(singlar)); + } + } + } else if(matchesPlural(singlar)) { + return singlar; + } else { + String msg = String.format("Noun '%s' doesn't belong to this inflection", singlar, this); + + throw new InflectionException(msg); + } + } + + private boolean matchesPlural(String noun) { + boolean hasModernPlural = modernPlural != null && modernPlural.hasAffix(noun); + + return hasModernPlural || (classicalPlural != null && classicalPlural.hasAffix(noun)); + } + + @Override + public String toString() { + return String.format(TOSTRING_FMT, singular, modernPlural, classicalPlural); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + + result = prime * result + ((classicalPlural == null) ? 0 : classicalPlural.hashCode()); + result = prime * result + ((modernPlural == null) ? 0 : modernPlural.hashCode()); + + return result; + } + + @Override + public boolean equals(Object obj) { + if(this == obj) return true; + if(obj == null) return false; + if(!(obj instanceof CategoricalNounInflection)) return false; + + CategoricalNounInflection other = (CategoricalNounInflection) obj; + + if(classicalPlural == null) { + if(other.classicalPlural != null) return false; + } else if(!classicalPlural.equals(other.classicalPlural)) return false; + + if(modernPlural == null) { + if(other.modernPlural != null) return false; + } else if(!modernPlural.equals(other.modernPlural)) return false; + + return true; + } + + @Override + public String pluralizeModern(String singlar) { + if(modernPlural == null) return pluralizeClassical(singlar); + + String actSinglar = singlar; + if(isPlural(singlar)) { + actSinglar = singularize(singlar); + } + + return modernPlural.affix(singular.deaffix(actSinglar)); + } + + @Override + public String pluralizeClassical(String singlar) { + if(classicalPlural == null) return pluralizeModern(singlar); + + String actSinglar = singlar; + if(isPlural(singlar)) { + actSinglar = singularize(singlar); + } + + return classicalPlural.affix(singular.deaffix(actSinglar)); + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/CompoundNounInflection.java b/src/main/java/bjc/inflexion/v2/CompoundNounInflection.java new file mode 100644 index 0000000..f82604e --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/CompoundNounInflection.java @@ -0,0 +1,170 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Implementation of {@link NounInflection} for words that don't inflect at the + * end. + * + * @author EVE + * + */ +public class CompoundNounInflection implements NounInflection { + /* + * Data stores for use. + */ + private Nouns nounDB; + private Prepositions prepositionDB; + + private Pattern compoundMatcher; + + private String singularPattern; + + private String modernPluralPattern; + private String classicalPluralPattern; + + private boolean preferClassical; + + /* + * Whether or not this inflection takes a preposition. + */ + private boolean hasPreposition; + + /** + * TODO fill in documentation. + * + * @param nounDB + * @param prepositionDB + * @param compoundMatcher + * @param singularPattern + * @param modernPluralPattern + * @param classicalPluralPattern + * @param preferClassical + * @param hasPreposition + */ + public CompoundNounInflection(Nouns nounDB, Prepositions prepositionDB, Pattern compoundMatcher, + String singularPattern, String modernPluralPattern, String classicalPluralPattern, + boolean preferClassical, boolean hasPreposition) { + this.nounDB = nounDB; + this.prepositionDB = prepositionDB; + this.compoundMatcher = compoundMatcher; + this.singularPattern = singularPattern; + this.modernPluralPattern = modernPluralPattern; + this.classicalPluralPattern = classicalPluralPattern; + this.preferClassical = preferClassical; + this.hasPreposition = hasPreposition; + } + + @Override + public boolean matches(String noun) { + Matcher matcher = compoundMatcher.matcher(noun); + + if(matcher.matches()) { + Noun actNoun = nounDB.getNoun(matcher.group("noun")); + + if(actNoun == null) return false; + + if(hasPreposition) { + return prepositionDB.isPreposition(matcher.group("preposition")); + } else + return true; + } else { + return false; + } + } + + @Override + public boolean isSingular(String noun) { + Matcher matcher = compoundMatcher.matcher(noun); + Noun actNoun = nounDB.getNoun(matcher.group("noun")); + + return actNoun.isSingular(); + } + + @Override + public boolean isPlural(String noun) { + Matcher matcher = compoundMatcher.matcher(noun); + Noun actNoun = nounDB.getNoun(matcher.group("noun")); + + return actNoun.isPlural(); + } + + @Override + public String singularize(String plural) { + Matcher matcher = compoundMatcher.matcher(plural); + Noun actNoun = nounDB.getNoun(matcher.group("noun")); + + if(hasPreposition) { + return String.format(singularPattern, actNoun.singular(), matcher.group("preposition")); + } else { + return String.format(singularPattern, actNoun.singular()); + } + } + + @Override + public String pluralize(String singular) { + Matcher matcher = compoundMatcher.matcher(singular); + Noun actNoun = getNoun(matcher); + + /* + * TODO adapt this to take preferClassical into account. + */ + if(hasPreposition) { + return String.format(modernPluralPattern, actNoun.plural(), matcher.group("preposition")); + } else { + return String.format(modernPluralPattern, actNoun.plural()); + } + } + + @Override + public String pluralizeModern(String singular) { + if(modernPluralPattern == null) return pluralizeClassical(singular); + + Matcher matcher = compoundMatcher.matcher(singular); + Noun actNoun = getNoun(matcher); + + if(hasPreposition) { + return String.format(modernPluralPattern, actNoun.modernPlural(), matcher.group("preposition")); + } else { + return String.format(modernPluralPattern, actNoun.modernPlural()); + } + } + + @Override + public String pluralizeClassical(String singular) { + if(modernPluralPattern == null) return pluralizeModern(singular); + + Matcher matcher = compoundMatcher.matcher(singular); + Noun actNoun = getNoun(matcher); + + if(hasPreposition) { + return String.format(classicalPluralPattern, actNoun.classicalPlural(), + matcher.group("preposition")); + } else { + return String.format(classicalPluralPattern, actNoun.classicalPlural()); + } + } + + private Noun getNoun(Matcher matcher) { + matcher.matches(); + + Noun actNoun = nounDB.getNoun(matcher.group("noun")); + return actNoun; + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/DefaultNounInflection.java b/src/main/java/bjc/inflexion/v2/DefaultNounInflection.java new file mode 100644 index 0000000..7c5a467 --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/DefaultNounInflection.java @@ -0,0 +1,68 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +/** + * Default noun inflection for english nouns. + * + * @author EVE + * + */ +public class DefaultNounInflection implements NounInflection { + @Override + public boolean matches(String noun) { + return true; + } + + @Override + public boolean isSingular(String noun) { + return !noun.endsWith("s"); + } + + @Override + public boolean isPlural(String noun) { + return noun.endsWith("s"); + } + + @Override + public String singularize(String plural) { + if(plural.endsWith("ses")) { + return plural.substring(0, plural.length() - 3); + } else if(plural.endsWith("s")) { + return plural.substring(0, plural.length() - 1); + } else + return plural; + } + + @Override + public String pluralize(String singular) { + if(singular.endsWith("s")) { + return singular + "es"; + } + + return singular + "s"; + } + + @Override + public String pluralizeModern(String singular) { + return pluralize(singular); + } + + @Override + public String pluralizeClassical(String singular) { + return pluralize(singular); + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/InflectionAffix.java b/src/main/java/bjc/inflexion/v2/InflectionAffix.java new file mode 100644 index 0000000..a9c583d --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/InflectionAffix.java @@ -0,0 +1,56 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +/** + * An affix attached to a word and used for inflection. + * + * @author EVE + * + */ +public interface InflectionAffix { + + /** + * Check if a word has this affix. + * + * @param word + * The word to check. + * + * @return Whether or not the word has the affix. + */ + boolean hasAffix(String word); + + /** + * Remove the affix from a word. + * + * @param word + * The word to remove the affix from. + * + * @return The word with the affix removed. + */ + String deaffix(String word); + + /** + * Apply this affix to a word. + * + * @param word + * The word to apply the affix to. + * + * @return The word with the affix applied. + */ + String affix(String word); + +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/InflectionAffixes.java b/src/main/java/bjc/inflexion/v2/InflectionAffixes.java new file mode 100644 index 0000000..b47af00 --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/InflectionAffixes.java @@ -0,0 +1,74 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +import java.util.regex.Pattern; + +/** + * Utility methods for constructing inflection affixes. + * + * @author EVE + * + */ +public class InflectionAffixes { + /* + * Template for 'complete' affix patterns. + * + * Match the start of the word, followed by zero or more word + * characters, followed by the suffix, then the end of the string. + * + * The word is in a capturing group named 'stem'. + */ + private static final String COMPLETE_PATT_FMT = "^(?<stem>\\w*)%s$"; + + /* + * Template for 'incomplete' affix patterns. + * + * Match the start of the word, followed by one or more word characters, + * followed by the suffix, then the end of the string. + * + * The word is in a capturing group named 'stem'. + */ + private static final String INCOMPLETE_PATT_FMT = "^(?<stem>\\w+)%s$"; + + /** + * Create an affix that's a word by itself. + * + * @param suffix + * The suffix to use. + * + * @return A affix that represents the suffix. + */ + public static InflectionAffix complete(String suffix) { + Pattern patt = Pattern.compile(String.format(COMPLETE_PATT_FMT, suffix)); + + return new SimpleInflectionAffix("%s" + suffix, patt); + } + + /** + * Create an affix that's not a word by itself. + * + * @param suffix + * The suffix to use. + * + * @return An affix that represents the suffix. + */ + public static InflectionAffix incomplete(String suffix) { + Pattern patt = Pattern.compile(String.format(INCOMPLETE_PATT_FMT, suffix)); + + return new SimpleInflectionAffix("%s" + suffix, patt); + } +} diff --git a/src/main/java/bjc/inflexion/v2/InflectionException.java b/src/main/java/bjc/inflexion/v2/InflectionException.java new file mode 100644 index 0000000..5974018 --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/InflectionException.java @@ -0,0 +1,49 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +/** + * Exception thrown when something goes wrong with inflection. + * + * @author EVE + * + */ +public class InflectionException extends RuntimeException { + private static final long serialVersionUID = 5680541587449153748L; + + /** + * Create a new inflection exception with the given message and cause. + * + * @param message + * The message of the exception. + * + * @param cause + * The cause of the exception. + */ + public InflectionException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Create a new inflection exception with the given message. + * + * @param message + * The message of the exception. + */ + public InflectionException(String message) { + super(message); + } +} diff --git a/src/main/java/bjc/inflexion/v2/IrregularNounInflection.java b/src/main/java/bjc/inflexion/v2/IrregularNounInflection.java new file mode 100644 index 0000000..294c6a3 --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/IrregularNounInflection.java @@ -0,0 +1,197 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +/** + * Implementation of {@link NounInflection} for irregular nouns. + * + * @author EVE + * + */ +public class IrregularNounInflection implements NounInflection { + private static final String TOSTRING_FMT = "IrregularNounInflection [singular=%s, modernPlural=%s," + + " classicalPlural=%s, preferClassical=%s]"; + + private String singular; + + private String modernPlural; + private String classicalPlural; + + private boolean preferClassical; + + /** + * Create a new irregular noun inflection. + * + * @param singlar + * The singular form of the noun. + * + * @param modrnPlural + * The modern plural of the noun. + * + * @param classiclPlural + * The classical plural of the noun. + * + * @param prefrClassical + * Whether the classical form should be preferred if it + * is available. + */ + public IrregularNounInflection(String singlar, String modrnPlural, String classiclPlural, + boolean prefrClassical) { + if(singlar == null) throw new NullPointerException("Singular form must not be null"); + if(modrnPlural == null && classiclPlural == null) + throw new NullPointerException("One of modern/classical plural forms must not be null"); + + singular = singlar; + modernPlural = modrnPlural; + classicalPlural = classiclPlural; + preferClassical = prefrClassical; + } + + @Override + public boolean matches(String noun) { + if(noun.equalsIgnoreCase(singular)) + return true; + else if(noun.equalsIgnoreCase(modernPlural)) + return true; + else if(noun.equalsIgnoreCase(classicalPlural)) + return true; + else + return false; + } + + @Override + public boolean isSingular(String noun) { + if(noun.equalsIgnoreCase(singular)) + return true; + else if(matchesPlural(noun)) + return false; + else { + String msg = String.format("Noun '%s' doesn't belong to this inflection '%s'", noun, this); + + throw new InflectionException(msg); + } + } + + @Override + public boolean isPlural(String noun) { + if(noun.equalsIgnoreCase(singular)) + return false; + else if(matchesPlural(noun)) + return true; + else { + String msg = String.format("Noun '%s' doesn't belong to this inflection '%s'", noun, this); + + throw new InflectionException(msg); + } + } + + @Override + public String singularize(String plural) { + if(plural.equalsIgnoreCase(singular)) + return singular; + else if(matchesPlural(plural)) + return singular; + else { + String msg = String.format("Noun '%s' doesn't belong to this inflection '%s'", plural, this); + + throw new InflectionException(msg); + } + } + + @Override + public String pluralize(String singular) { + if(singular.equalsIgnoreCase(singular)) + return getPlural(); + else if(matchesPlural(singular)) + return getPlural(); + else { + String msg = String.format("Noun '%s' doesn't belong to this inflection '%s'", singular, this); + + throw new InflectionException(msg); + } + } + + private String getPlural() { + if(preferClassical) { + if(classicalPlural == null) + return modernPlural; + else + return classicalPlural; + } else if(modernPlural == null) { + return classicalPlural; + } else { + return modernPlural; + } + } + + private boolean matchesPlural(String noun) { + return noun.equalsIgnoreCase(modernPlural) || noun.equalsIgnoreCase(classicalPlural); + } + + @Override + public String toString() { + return String.format(TOSTRING_FMT, singular, modernPlural, classicalPlural, preferClassical); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + + result = prime * result + ((classicalPlural == null) ? 0 : classicalPlural.hashCode()); + result = prime * result + ((modernPlural == null) ? 0 : modernPlural.hashCode()); + result = prime * result + ((singular == null) ? 0 : singular.hashCode()); + + return result; + } + + @Override + public boolean equals(Object obj) { + if(this == obj) return true; + if(obj == null) return false; + if(!(obj instanceof IrregularNounInflection)) return false; + + IrregularNounInflection other = (IrregularNounInflection) obj; + + if(singular == null) { + if(other.singular != null) return false; + } else if(!singular.equals(other.singular)) return false; + + if(classicalPlural == null) { + if(other.classicalPlural != null) return false; + } else if(!classicalPlural.equals(other.classicalPlural)) return false; + + if(modernPlural == null) { + if(other.modernPlural != null) return false; + } else if(!modernPlural.equals(other.modernPlural)) return false; + + return true; + } + + @Override + public String pluralizeModern(String singular) { + if(modernPlural == null) return pluralizeClassical(singular); + + return modernPlural; + } + + @Override + public String pluralizeClassical(String singular) { + if(classicalPlural == null) return pluralizeModern(singular); + + return classicalPlural; + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/Noun.java b/src/main/java/bjc/inflexion/v2/Noun.java new file mode 100644 index 0000000..bf74613 --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/Noun.java @@ -0,0 +1,121 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +/** + * A noun attached to an inflection. + * + * @author EVE + * + */ +public class Noun { + private static final String TOSTRING_FMT = "Noun [word=%s, inflection=%s]"; + + private final String word; + + private final NounInflection inflection; + + /** + * Create a new noun from a word and inflection. + * + * @param wrd + * The word for the noun. + * + * @param inflction + * The inflection for the word. + */ + public Noun(String wrd, NounInflection inflction) { + word = wrd; + inflection = inflction; + } + + /** + * Get the input noun. + * + * @return The noun, as input. + */ + public String getWord() { + return word; + } + + /** + * Get the inflection for this noun. + * + * @return The inflection for this noun. + */ + public NounInflection getInflection() { + return inflection; + } + + /** + * Check if this noun is singular. + * + * @return Whether or not the noun is singular. + */ + public boolean isSingular() { + return inflection.isSingular(word); + } + + /** + * Check if this noun is plural. + * + * @return Whether or not this noun is plural. + */ + public boolean isPlural() { + return inflection.isPlural(word); + } + + /** + * Get the singular form of this noun. + * + * @return The singular form of this noun. + */ + public String singular() { + return inflection.singularize(word); + } + + /** + * Get the plural form of this noun. + * + * @return The plural form of this noun. + */ + public String plural() { + return inflection.pluralize(word); + } + + @Override + public String toString() { + return String.format(TOSTRING_FMT, word, inflection); + } + + /** + * Get the modern plural form of this noun. + * + * @return The modern plural form of this noun. + */ + public String modernPlural() { + return inflection.pluralizeModern(word); + } + + /** + * Get the classical plural form of this noun. + * + * @return The classical plural form of this noun. + */ + public String classicalPlural() { + return inflection.pluralizeClassical(word); + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/NounInflection.java b/src/main/java/bjc/inflexion/v2/NounInflection.java new file mode 100644 index 0000000..2a4049f --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/NounInflection.java @@ -0,0 +1,113 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +/** + * Interface for inflecting nouns. + * + * @author EVE + * + */ +public interface NounInflection { + /** + * Check if a noun matches this inflection. + * + * @param noun + * The noun to check on this inflection. + * + * @return Whether or not the noun belongs to the inflection. + */ + public boolean matches(String noun); + + /** + * Check if a noun for this inflection is singular or not. + * + * @param noun + * The noun to check for singularity. + * + * @return Whether or not the noun is singular. + * + * @throws InflectionException + * If the noun isn't part of this inflection. + */ + public boolean isSingular(String noun); + + /** + * Check if a noun for this inflection is plural or not. + * + * @param noun + * The noun to check for plurality. + * + * @return Whether or not the noun is plural. + * + * @throws InflectionException + * If the noun isn't part of this inflection. + */ + public boolean isPlural(String noun); + + /** + * Convert a singular noun to a plural noun. + * + * @param plural + * The plural noun to inflect to a singular form. + * + * @return The singular form of the noun. + * + * @throws InflectionException + * If the noun isn't part of the inflection. + */ + public String singularize(String plural); + + /** + * Convert a singular noun to a plural noun. + * + * @param singular + * The singular noun to inflect to a plural form. + * + * @return The plural form of the noun. + * + * @throws InflectionException + * If the noun isn't part of the inflection. + */ + public String pluralize(String singular); + + /** + * Convert a singular noun to a modern plural noun. + * + * @param singular + * The singular noun to inflect to a modern plural form. + * + * @return The modern plural form of the noun. + * + * @throws InflectionException + * If the noun isn't part of the inflection. + */ + public String pluralizeModern(String singular); + + /** + * Convert a singular noun to a classical plural noun. + * + * @param singular + * The singular noun to inflect to a classical plural + * form. + * + * @return The classical plural form of the noun. + * + * @throws InflectionException + * If the noun isn't part of the inflection. + */ + public String pluralizeClassical(String singular); +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/Nouns.java b/src/main/java/bjc/inflexion/v2/Nouns.java new file mode 100644 index 0000000..6645d5c --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/Nouns.java @@ -0,0 +1,183 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.regex.Pattern; + +import static bjc.inflexion.v2.InflectionAffixes.*; + +/** + * @author EVE + * + */ +public class Nouns { + private static final DefaultNounInflection DEFAULT_INFLECTION = new DefaultNounInflection(); + + private Map<String, NounInflection> userIrregulars; + private List<NounInflection> userInflections; + + private Map<String, NounInflection> predefinedIrregulars; + private List<NounInflection> predefinedInflections; + + /** + * Create a new empty noun DB. + */ + public Nouns() { + userIrregulars = new HashMap<>(); + userInflections = new LinkedList<>(); + + predefinedIrregulars = new HashMap<>(); + predefinedInflections = new LinkedList<>(); + } + + /** + * Retrieve a noun with its inflection from the database of inflections. + * + * @param noun + * The noun to retrieve. + * + * @return The noun with its inflection. + * + * @throws InflectionException + * If the noun matched no inflection. + */ + public Noun getNoun(String noun) { + if(userIrregulars.containsKey(noun)) return new Noun(noun, userIrregulars.get(noun)); + for(NounInflection inflect : userInflections) { + if(inflect.matches(noun)) return new Noun(noun, inflect); + } + + if(predefinedIrregulars.containsKey(noun)) return new Noun(noun, predefinedIrregulars.get(noun)); + for(NounInflection inflect : predefinedInflections) { + if(inflect.matches(noun)) return new Noun(noun, inflect); + } + + return new Noun(noun, DEFAULT_INFLECTION); + } + + /** + * Load the contents of the stream into this DB. + * + * @param stream + * The stream to load from. + */ + public void loadFromStream(InputStream stream) { + try(Scanner scn = new Scanner(stream)) { + while(scn.hasNextLine()) { + String ln = scn.nextLine().trim(); + + /* + * Ignore comments and blank lines. + */ + if(ln.startsWith("#")) continue; + if(ln.equals("")) continue; + + handleLine(ln); + } + } + } + + private void handleLine(String ln) { + String[] parts = ln.split(Pattern.quote("=>")); + + if(parts.length != 2) { + String msg = String.format("Improperly formatted noun defn '%s'", ln); + + throw new InflectionException(msg); + } + + String singular = parts[0].trim(); + String plural = parts[1].trim(); + + String modernPlural = ""; + String classicalPlural = ""; + + if(plural.contains("|")) { + String[] plurals = plural.split(Pattern.quote("|")); + + if(plurals.length == 1) { + modernPlural = plurals[0].trim(); + } else { + modernPlural = plurals[0].trim(); + classicalPlural = plurals[1].trim(); + } + + if(modernPlural.equals("")) modernPlural = null; + if(classicalPlural.equals("")) classicalPlural = null; + } else { + modernPlural = plural; + classicalPlural = null; + } + + if(singular.startsWith("*")) { + handleCompletePlural(singular, modernPlural, classicalPlural); + } else if(singular.startsWith("-")) { + handleIncompletePlural(singular, modernPlural, classicalPlural); + } else { + handleIrregularPlural(singular, modernPlural, classicalPlural); + } + } + + private void handleIncompletePlural(String singular, String modernPlural, String classicalPlural) { + InflectionAffix singularAffix = incomplete(singular.substring(1)); + + InflectionAffix modernAffix = null; + InflectionAffix classicalAffix = null; + + if(modernPlural != null) modernAffix = incomplete(modernPlural.substring(1)); + if(classicalPlural != null) classicalAffix = incomplete(classicalPlural.substring(1)); + + CategoricalNounInflection inflection = new CategoricalNounInflection(singularAffix, modernAffix, + classicalAffix, false); + + predefinedInflections.add(inflection); + } + + private void handleCompletePlural(String singular, String modernPlural, String classicalPlural) { + InflectionAffix singularAffix = complete(singular.substring(1)); + + InflectionAffix modernAffix = null; + InflectionAffix classicalAffix = null; + + if(modernPlural != null) modernAffix = complete(modernPlural.substring(1)); + if(classicalPlural != null) classicalAffix = complete(classicalPlural.substring(1)); + + CategoricalNounInflection inflection = new CategoricalNounInflection(singularAffix, modernAffix, + classicalAffix, false); + + predefinedInflections.add(inflection); + } + + private void handleIrregularPlural(String singular, String modernPlural, String classicalPlural) { + IrregularNounInflection inflection = new IrregularNounInflection(singular, modernPlural, + classicalPlural, false); + + if(!predefinedIrregulars.containsKey(singular)) { + predefinedIrregulars.put(singular, inflection); + } + + if(modernPlural != null && !predefinedIrregulars.containsKey(modernPlural)) + predefinedIrregulars.put(modernPlural, inflection); + if(classicalPlural != null && !predefinedIrregulars.containsKey(classicalPlural)) + predefinedIrregulars.put(classicalPlural, inflection); + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/Prepositions.java b/src/main/java/bjc/inflexion/v2/Prepositions.java new file mode 100644 index 0000000..042ab8a --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/Prepositions.java @@ -0,0 +1,71 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +import java.io.InputStream; +import java.util.HashSet; +import java.util.Scanner; +import java.util.Set; + +/** + * List of prepositions. + * + * @author EVE + * + */ +public class Prepositions { + private Set<String> prepositions; + + /** + * Create an empty preposition DB. + */ + public Prepositions() { + prepositions = new HashSet<>(); + } + + /** + * Check if a word is a preposition. + * + * @param word + * The word as a preposition. + * + * @return Whether or not the word is a preposition. + */ + public boolean isPreposition(String word) { + return prepositions.contains(word); + } + + /** + * Load the contents of the stream into this DB. + * + * @param stream + * The stream to load from. + */ + public void loadFromStream(InputStream stream) { + try(Scanner scn = new Scanner(stream)) { + while(scn.hasNextLine()) { + String ln = scn.nextLine().trim(); + + /* + * Ignore comments + */ + if(ln.startsWith("#")) continue; + + prepositions.add(ln); + } + } + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/inflexion/v2/SimpleInflectionAffix.java b/src/main/java/bjc/inflexion/v2/SimpleInflectionAffix.java new file mode 100644 index 0000000..623c93c --- /dev/null +++ b/src/main/java/bjc/inflexion/v2/SimpleInflectionAffix.java @@ -0,0 +1,103 @@ +/** + * (C) Copyright 2017 Benjamin Culkin. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package bjc.inflexion.v2; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Simple implementation of {@link InflectionAffix} + * + * @author EVE + * + */ +public class SimpleInflectionAffix implements InflectionAffix { + private static final String TOSTRING_FMT = "SimpleInflectionAffix [affixTemplate=%s, affixMatcher=%s]"; + + private String affixTemplate; + + private Pattern affixMatcher; + + /** + * Create a new inflection affix. + * + * @param affixTemplate + * The template for applying the affix, Should be a + * printf-style format string with a single string blank. + * + * @param affixMatcher + * The regular expression that matches the affix on + * strings. The 'stem' or word should be placed in a + * named capturing group named 'stem'. + */ + public SimpleInflectionAffix(String affixTemplate, Pattern affixMatcher) { + this.affixTemplate = affixTemplate; + this.affixMatcher = affixMatcher; + } + + @Override + public boolean hasAffix(String word) { + return affixMatcher.matcher(word).matches(); + } + + @Override + public String deaffix(String word) { + Matcher matcher = affixMatcher.matcher(word); + matcher.matches(); + + return matcher.group("stem"); + } + + @Override + public String affix(String word) { + return String.format(affixTemplate, word); + } + + @Override + public String toString() { + return String.format(TOSTRING_FMT, affixTemplate, affixMatcher); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + + result = prime * result + ((affixMatcher == null) ? 0 : affixMatcher.hashCode()); + result = prime * result + ((affixTemplate == null) ? 0 : affixTemplate.hashCode()); + + return result; + } + + @Override + public boolean equals(Object obj) { + if(this == obj) return true; + if(obj == null) return false; + if(!(obj instanceof SimpleInflectionAffix)) return false; + + SimpleInflectionAffix other = (SimpleInflectionAffix) obj; + + if(affixTemplate == null) { + if(other.affixTemplate != null) return false; + } else if(!affixTemplate.equals(other.affixTemplate)) return false; + + if(affixMatcher == null) { + if(other.affixMatcher != null) return false; + } else if(!affixMatcher.equals(other.affixMatcher)) return false; + + return true; + } +}
\ No newline at end of file |
