Correctly generate plurals, ordinals, indefinite articles; convert numbers to words

Overview
Automated Tests Code style: Black https://coveralls.io/repos/github/jaraco/inflect/badge.svg?branch=master https://tidelift.com/badges/package/pypi/inflect

NAME

inflect.py - Correctly generate plurals, singular nouns, ordinals, indefinite articles; convert numbers to words.

SYNOPSIS

import inflect

p = inflect.engine()

# METHODS:

# plural plural_noun plural_verb plural_adj singular_noun no num
# compare compare_nouns compare_nouns compare_adjs
# a an
# present_participle
# ordinal number_to_words
# join
# inflect classical gender
# defnoun defverb defadj defa defan


# UNCONDITIONALLY FORM THE PLURAL

print("The plural of ", word, " is ", p.plural(word))


# CONDITIONALLY FORM THE PLURAL

print("I saw", cat_count, p.plural("cat", cat_count))


# FORM PLURALS FOR SPECIFIC PARTS OF SPEECH

print(
    p.plural_noun("I", N1),
    p.plural_verb("saw", N1),
    p.plural_adj("my", N2),
    p.plural_noun("saw", N2),
)


# FORM THE SINGULAR OF PLURAL NOUNS

print("The singular of ", word, " is ", p.singular_noun(word))

# SELECT THE GENDER OF SINGULAR PRONOUNS

print(p.singular_noun("they"))  # 'it'
p.gender("f")
print(p.singular_noun("they"))  # 'she'


# DEAL WITH "0/1/N" -> "no/1/N" TRANSLATION:

print("There ", p.plural_verb("was", errors), p.no(" error", errors))


# USE DEFAULT COUNTS:

print(
    p.num(N1, ""),
    p.plural("I"),
    p.plural_verb(" saw"),
    p.num(N2),
    p.plural_noun(" saw"),
)
print("There ", p.num(errors, ""), p.plural_verb("was"), p.no(" error"))


# COMPARE TWO WORDS "NUMBER-INSENSITIVELY":

if p.compare(word1, word2):
    print("same")
if p.compare_nouns(word1, word2):
    print("same noun")
if p.compare_verbs(word1, word2):
    print("same verb")
if p.compare_adjs(word1, word2):
    print("same adj.")


# ADD CORRECT "a" OR "an" FOR A GIVEN WORD:

print("Did you want ", p.a(thing), " or ", p.an(idea))


# CONVERT NUMERALS INTO ORDINALS (i.e. 1->1st, 2->2nd, 3->3rd, etc.)

print("It was", p.ordinal(position), " from the left\n")

# CONVERT NUMERALS TO WORDS (i.e. 1->"one", 101->"one hundred and one", etc.)
# RETURNS A SINGLE STRING...

words = p.number_to_words(1234)
# "one thousand, two hundred and thirty-four"
words = p.number_to_words(p.ordinal(1234))
# "one thousand, two hundred and thirty-fourth"


# GET BACK A LIST OF STRINGS, ONE FOR EACH "CHUNK"...

words = p.number_to_words(1234, wantlist=True)
# ("one thousand","two hundred and thirty-four")


# OPTIONAL PARAMETERS CHANGE TRANSLATION:

words = p.number_to_words(12345, group=1)
# "one, two, three, four, five"

words = p.number_to_words(12345, group=2)
# "twelve, thirty-four, five"

words = p.number_to_words(12345, group=3)
# "one twenty-three, forty-five"

words = p.number_to_words(1234, andword="")
# "one thousand, two hundred thirty-four"

words = p.number_to_words(1234, andword=", plus")
# "one thousand, two hundred, plus thirty-four"
# TODO: I get no comma before plus: check perl

words = p.number_to_words(555_1202, group=1, zero="oh")
# "five, five, five, one, two, oh, two"

words = p.number_to_words(555_1202, group=1, one="unity")
# "five, five, five, unity, two, oh, two"

words = p.number_to_words(123.456, group=1, decimal="mark")
# "one two three mark four five six"
# TODO: DOCBUG: perl gives commas here as do I

# LITERAL STYLE ONLY NAMES NUMBERS LESS THAN A CERTAIN THRESHOLD...

words = p.number_to_words(9, threshold=10)  # "nine"
words = p.number_to_words(10, threshold=10)  # "ten"
words = p.number_to_words(11, threshold=10)  # "11"
words = p.number_to_words(1000, threshold=10)  # "1,000"

# JOIN WORDS INTO A LIST:

mylist = join(("apple", "banana", "carrot"))
# "apple, banana, and carrot"

mylist = join(("apple", "banana"))
# "apple and banana"

mylist = join(("apple", "banana", "carrot"), final_sep="")
# "apple, banana and carrot"


# REQUIRE "CLASSICAL" PLURALS (EG: "focus"->"foci", "cherub"->"cherubim")

p.classical()  # USE ALL CLASSICAL PLURALS

p.classical(all=True)  # USE ALL CLASSICAL PLURALS
p.classical(all=False)  # SWITCH OFF CLASSICAL MODE

p.classical(zero=True)  #  "no error" INSTEAD OF "no errors"
p.classical(zero=False)  #  "no errors" INSTEAD OF "no error"

p.classical(herd=True)  #  "2 buffalo" INSTEAD OF "2 buffalos"
p.classical(herd=False)  #  "2 buffalos" INSTEAD OF "2 buffalo"

p.classical(persons=True)  # "2 chairpersons" INSTEAD OF "2 chairpeople"
p.classical(persons=False)  # "2 chairpeople" INSTEAD OF "2 chairpersons"

p.classical(ancient=True)  # "2 formulae" INSTEAD OF "2 formulas"
p.classical(ancient=False)  # "2 formulas" INSTEAD OF "2 formulae"


# INTERPOLATE "plural()", "plural_noun()", "plural_verb()", "plural_adj()", "singular_noun()",
# a()", "an()", "num()" AND "ordinal()" WITHIN STRINGS:

print(p.inflect("The plural of {0} is plural('{0}')".format(word)))
print(p.inflect("The singular of {0} is singular_noun('{0}')".format(word)))
print(p.inflect("I saw {0} plural('cat',{0})".format(cat_count)))
print(
    p.inflect(
        "plural('I',{0}) "
        "plural_verb('saw',{0}) "
        "plural('a',{1}) "
        "plural_noun('saw',{1})".format(N1, N2)
    )
)
print(
    p.inflect(
        "num({0}, False)plural('I') "
        "plural_verb('saw') "
        "num({1}, False)plural('a') "
        "plural_noun('saw')".format(N1, N2)
    )
)
print(p.inflect("I saw num({0}) plural('cat')\nnum()".format(cat_count)))
print(p.inflect("There plural_verb('was',{0}) no('error',{0})".format(errors)))
print(p.inflect("There num({0}, False)plural_verb('was') no('error')".format(errors)))
print(p.inflect("Did you want a('{0}') or an('{1}')".format(thing, idea)))
print(p.inflect("It was ordinal('{0}') from the left".format(position)))


# ADD USER-DEFINED INFLECTIONS (OVERRIDING INBUILT RULES):

p.defnoun("VAX", "VAXen")  # SINGULAR => PLURAL

p.defverb(
    "will",  # 1ST PERSON SINGULAR
    "shall",  # 1ST PERSON PLURAL
    "will",  # 2ND PERSON SINGULAR
    "will",  # 2ND PERSON PLURAL
    "will",  # 3RD PERSON SINGULAR
    "will",  # 3RD PERSON PLURAL
)

p.defadj("hir", "their")  # SINGULAR => PLURAL

p.defa("h")  # "AY HALWAYS SEZ 'HAITCH'!"

p.defan("horrendous.*")  # "AN HORRENDOUS AFFECTATION"

DESCRIPTION

The methods of the class engine in module inflect.py provide plural inflections, singular noun inflections, "a"/"an" selection for English words, and manipulation of numbers as words.

Plural forms of all nouns, most verbs, and some adjectives are provided. Where appropriate, "classical" variants (for example: "brother" -> "brethren", "dogma" -> "dogmata", etc.) are also provided.

Single forms of nouns are also provided. The gender of singular pronouns can be chosen (for example "they" -> "it" or "she" or "he" or "they").

Pronunciation-based "a"/"an" selection is provided for all English words, and most initialisms.

It is also possible to inflect numerals (1,2,3) to ordinals (1st, 2nd, 3rd) and to English words ("one", "two", "three").

In generating these inflections, inflect.py follows the Oxford English Dictionary and the guidelines in Fowler's Modern English Usage, preferring the former where the two disagree.

The module is built around standard British spelling, but is designed to cope with common American variants as well. Slang, jargon, and other English dialects are not explicitly catered for.

Where two or more inflected forms exist for a single word (typically a "classical" form and a "modern" form), inflect.py prefers the more common form (typically the "modern" one), unless "classical" processing has been specified (see MODERN VS CLASSICAL INFLECTIONS).

FORMING PLURALS AND SINGULARS

Inflecting Plurals and Singulars

All of the plural... plural inflection methods take the word to be inflected as their first argument and return the corresponding inflection. Note that all such methods expect the singular form of the word. The results of passing a plural form are undefined (and unlikely to be correct). Similarly, the si... singular inflection method expects the plural form of the word.

The plural... methods also take an optional second argument, which indicates the grammatical "number" of the word (or of another word with which the word being inflected must agree). If the "number" argument is supplied and is not 1 (or "one" or "a", or some other adjective that implies the singular), the plural form of the word is returned. If the "number" argument does indicate singularity, the (uninflected) word itself is returned. If the number argument is omitted, the plural form is returned unconditionally.

The si... method takes a second argument in a similar fashion. If it is some form of the number 1, or is omitted, the singular form is returned. Otherwise the plural is returned unaltered.

The various methods of inflect.engine are:

plural_noun(word, count=None)

The method plural_noun() takes a singular English noun or pronoun and returns its plural. Pronouns in the nominative ("I" -> "we") and accusative ("me" -> "us") cases are handled, as are possessive pronouns ("mine" -> "ours").

plural_verb(word, count=None)

The method plural_verb() takes the singular form of a conjugated verb (that is, one which is already in the correct "person" and "mood") and returns the corresponding plural conjugation.

plural_adj(word, count=None)

The method plural_adj() takes the singular form of certain types of adjectives and returns the corresponding plural form. Adjectives that are correctly handled include: "numerical" adjectives ("a" -> "some"), demonstrative adjectives ("this" -> "these", "that" -> "those"), and possessives ("my" -> "our", "cat's" -> "cats'", "child's" -> "childrens'", etc.)

plural(word, count=None)

The method plural() takes a singular English noun, pronoun, verb, or adjective and returns its plural form. Where a word has more than one inflection depending on its part of speech (for example, the noun "thought" inflects to "thoughts", the verb "thought" to "thought"), the (singular) noun sense is preferred to the (singular) verb sense.

Hence plural("knife") will return "knives" ("knife" having been treated as a singular noun), whereas plural("knifes") will return "knife" ("knifes" having been treated as a 3rd person singular verb).

The inherent ambiguity of such cases suggests that, where the part of speech is known, plural_noun, plural_verb, and plural_adj should be used in preference to plural.

singular_noun(word, count=None)

The method singular_noun() takes a plural English noun or pronoun and returns its singular. Pronouns in the nominative ("we" -> "I") and accusative ("us" -> "me") cases are handled, as are possessive pronouns ("ours" -> "mine"). When third person singular pronouns are returned they take the neuter gender by default ("they" -> "it"), not ("they"-> "she") nor ("they" -> "he"). This can be changed with gender().

Note that all these methods ignore any whitespace surrounding the word being inflected, but preserve that whitespace when the result is returned. For example, plural(" cat ") returns " cats ".

gender(genderletter)

The third person plural pronoun takes the same form for the female, male and neuter (e.g. "they"). The singular however, depends upon gender (e.g. "she", "he", "it" and "they" -- "they" being the gender neutral form.) By default singular_noun returns the neuter form, however, the gender can be selected with the gender method. Pass the first letter of the gender to gender to return the f(eminine), m(asculine), n(euter) or t(hey) form of the singular. e.g. gender('f') followed by singular_noun('themselves') returns 'herself'.

Numbered plurals

The plural... methods return only the inflected word, not the count that was used to inflect it. Thus, in order to produce "I saw 3 ducks", it is necessary to use:

print("I saw", N, p.plural_noun(animal, N))

Since the usual purpose of producing a plural is to make it agree with a preceding count, inflect.py provides a method (no(word, count)) which, given a word and a(n optional) count, returns the count followed by the correctly inflected word. Hence the previous example can be rewritten:

print("I saw ", p.no(animal, N))

In addition, if the count is zero (or some other term which implies zero, such as "zero", "nil", etc.) the count is replaced by the word "no". Hence, if N had the value zero, the previous example would print (the somewhat more elegant):

I saw no animals

rather than:

I saw 0 animals

Note that the name of the method is a pun: the method returns either a number (a No.) or a "no", in front of the inflected word.

Reducing the number of counts required

In some contexts, the need to supply an explicit count to the various plural... methods makes for tiresome repetition. For example:

print(
    plural_adj("This", errors),
    plural_noun(" error", errors),
    plural_verb(" was", errors),
    " fatal.",
)

inflect.py therefore provides a method (num(count=None, show=None)) which may be used to set a persistent "default number" value. If such a value is set, it is subsequently used whenever an optional second "number" argument is omitted. The default value thus set can subsequently be removed by calling num() with no arguments. Hence we could rewrite the previous example:

p.num(errors)
print(p.plural_adj("This"), p.plural_noun(" error"), p.plural_verb(" was"), "fatal.")
p.num()

Normally, num() returns its first argument, so that it may also be "inlined" in contexts like:

print(p.num(errors), p.plural_noun(" error"), p.plural_verb(" was"), " detected.")
if severity > 1:
    print(
        p.plural_adj("This"), p.plural_noun(" error"), p.plural_verb(" was"), "fatal."
    )

However, in certain contexts (see INTERPOLATING INFLECTIONS IN STRINGS) it is preferable that num() return an empty string. Hence num() provides an optional second argument. If that argument is supplied (that is, if it is defined) and evaluates to false, num returns an empty string instead of its first argument. For example:

print(p.num(errors, 0), p.no("error"), p.plural_verb(" was"), " detected.")
if severity > 1:
    print(
        p.plural_adj("This"), p.plural_noun(" error"), p.plural_verb(" was"), "fatal."
    )

Number-insensitive equality

inflect.py also provides a solution to the problem of comparing words of differing plurality through the methods compare(word1, word2), compare_nouns(word1, word2), compare_verbs(word1, word2), and compare_adjs(word1, word2). Each of these methods takes two strings, and compares them using the corresponding plural-inflection method (plural(), plural_noun(), plural_verb(), and plural_adj() respectively).

The comparison returns true if:

  • the strings are equal, or
  • one string is equal to a plural form of the other, or
  • the strings are two different plural forms of the one word.

Hence all of the following return true:

p.compare("index", "index")  # RETURNS "eq"
p.compare("index", "indexes")  # RETURNS "s:p"
p.compare("index", "indices")  # RETURNS "s:p"
p.compare("indexes", "index")  # RETURNS "p:s"
p.compare("indices", "index")  # RETURNS "p:s"
p.compare("indices", "indexes")  # RETURNS "p:p"
p.compare("indexes", "indices")  # RETURNS "p:p"
p.compare("indices", "indices")  # RETURNS "eq"

As indicated by the comments in the previous example, the actual value returned by the various compare methods encodes which of the three equality rules succeeded: "eq" is returned if the strings were identical, "s:p" if the strings were singular and plural respectively, "p:s" for plural and singular, and "p:p" for two distinct plurals. Inequality is indicated by returning an empty string.

It should be noted that two distinct singular words which happen to take the same plural form are not considered equal, nor are cases where one (singular) word's plural is the other (plural) word's singular. Hence all of the following return false:

p.compare("base", "basis")  # ALTHOUGH BOTH -> "bases"
p.compare("syrinx", "syringe")  # ALTHOUGH BOTH -> "syringes"
p.compare("she", "he")  # ALTHOUGH BOTH -> "they"

p.compare("opus", "operas")  # ALTHOUGH "opus" -> "opera" -> "operas"
p.compare("taxi", "taxes")  # ALTHOUGH "taxi" -> "taxis" -> "taxes"

Note too that, although the comparison is "number-insensitive" it is not case-insensitive (that is, plural("time","Times") returns false. To obtain both number and case insensitivity, use the lower() method on both strings (that is, plural("time".lower(), "Times".lower()) returns true).

Related Functionality

Shout out to these libraries that provide related functionality:

  • WordSet parses identifiers like variable names into sets of words suitable for re-assembling in another form.
  • word2number converts words to a number.

For Enterprise

Available as part of the Tidelift Subscription.

This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.

Learn more.

Security Contact

To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure.

Comments
  • Add Travis CI and Coveralls

    Add Travis CI and Coveralls

    I've added a configuration file so Travis CI will build each commit and pull request. It runs against each Python version supported by Travis CI: 2.6, 2.7, 3.2, 3.3, 3.4, PyPy and PyPy3, and all of them pass with no changes needed. This will help maintain the codebase by automatically running the tests against all Python versions for each PR -- it's very handy for picking up those Py2/Py3 inconsistencies..

    It also runs the tests with coverage enabled, and sends the coverage reports to Coveralls, so you can see how coverage changes, or if a PR doesn't include tests to cover its new code. Right now, inflect.py has an amazing 98% coverage!

    You get reports like this:

    • https://travis-ci.org/hugovk/inflect.py
    • https://coveralls.io/r/hugovk/inflect.py

    I've added badges to the README to show off how good stats this project has. Both Travis CI and Coveralls are free for open source project, you just need to enable them for the repo. Please can you do so at:

    • https://travis-ci.org/profile
    • https://coveralls.io/repos/new

    Thanks!

    opened by hugovk 18
  • Allow special case dictionaries to match on lowercase final word

    Allow special case dictionaries to match on lowercase final word

    While inflecting some ingredient-related content, I'd noticed that although the word olives is currently handled correctly by singular_noun, black olives is not:

    >>> import inflect
    >>> inflect.__version__
    '4.0.0'
    >>> e = inflect.engine()
    >>> e.singular_noun('olives')
    'olive'
    >>> e.singular_noun('black olives')
    'black olife'
    

    In the inflect code, the handling of single-word olives is performed by a special case which overrides the default logic for items ending ...ves.

    This is one of a number of special cases gated by boolean conditions of the form if lowerword in <map>:, which fail if lowerword doesn't exactly match with a key in the <map>.

    Switching these conditions to use lowerwordlast instead of lowerword results in additional matches for multi-word phrases without negatively impacting any existing test cases.

    It's arguably not 'perfect' since multi-word phrases may have challenging plurality rules (like the situations handled by the compound logic, but hopefully it's a reasonably safe improvement.

    This also resolves https://github.com/jazzband/inflect/issues/30 which falls into a similar special case relating to ...ies tokens.

    opened by jayaddison 14
  • Implement Jazzband guidelines for project inflect.py

    Implement Jazzband guidelines for project inflect.py

    This issue tracks the implementation of the Jazzband guidelines for the project inflect.py

    It was initiated by @jaraco who was automatically assigned in addition to the Jazzband roadies.

    See the TODO list below for the generally required tasks, but feel free to update it in case the project requires it.

    Feel free to ping a Jazzband roadie if you have any question.

    TODOs

    • [x] Fix all links in the docs (and README file etc) from old to new repo
    • [x] Add the Jazzband badge to the README file
    • [x] Add the Jazzband contributing guideline to the CONTRIBUTING.md file
    • [x] Check if continuous testing works (e.g. Travis-CI, CircleCI, AppVeyor, etc)
    • [x] Check if test coverage services work (e.g. Coveralls, Codecov, etc)
    • [x] Add jazzband account to PyPI project as maintainer role (URL: https://pypi.python.org/pypi?:action=role_form&package_name=<PROJECTNAME>)
    • [x] Add jazzband-bot as maintainer to the Read the Docs project (URL: https://readthedocs.org/dashboard/<PROJECTNAME>/users/)
    • [x] Fix project URL in GitHub project description
    • [x] Review project if other services are used and port them to Jazzband

    Project details

    Description Correctly generate plurals, ordinals, indefinite articles; convert numbers to words
    Homepage http://pypi.python.org/pypi/inflect
    Stargazers 0
    Open issues 0
    Forks 0
    Default branch master
    Is a fork True
    Has Wiki True
    Has Pages False
    opened by jazzband-bot 13
  • Transfer project to jaraco

    Transfer project to jaraco

    Given the ~~lack of support for Azure pipelines (#101)~~, the ~~less streamlined process for releases (#80)~~, and the exclusion of sponsorship for these projects (#102), the inclusion of this project in Jazzband is now more of a hindrance than a benefit.

    @jezdez Would you please transfer the project back to /jaraco?

    opened by jaraco 11
  • Plural issues?

    Plural issues?

    Some are wrong, I think:

    >>> p.plural('corpus')  # corpora
    'corpuses'
    >>> p.plural('means')  # means
    'mean'
    >>> p.plural('vita')   # vitae
    'vitas'
    >>> p.plural('backhoe')
    'backhoes'
    >>> p.plural('hoe')  # hoes
    'ho'
    >>> p.plural('ho')   # hos
    'h'
    

    These are technically correct, but unusual (and not a mistake like the octupus-plural):

    >>> p.plural('radius')  # radii, radiuses
    'radiuses'
    >>> p.plural('curriculum')  # curricula, curriculums
    'curriculums'
    >>> p.plural('medium')  # mediums, media
    'mediums'
    >>> p.plural('appendix')  # appendixes, appendices
    'appendixes'
    # also index
    

    Not sure how it should work for uncountables:

    >>> p.plural('cattle')  # cattle        
    'cattles'
    
    help wanted 
    opened by mbr 11
  • query of death

    query of death

    On version 2.1.0 This string: "lens with a lens ()." yields an exception.

    > /lib/python3.6/site-packages/inflect.py in plural(self, text, count)
    >    2239             self._pl_special_adjective(word, count)
    >    2240             or self._pl_special_verb(word, count)
    > -> 2241             or self._plnoun(word, count),
    >    2242         )
    >    2243         return "{}{}{}".format(pre, plural, post)
    > 
    > /lib/python3.6/site-packages/inflect.py in postprocess(self, orig, inflected)
    >    2209                 continue
    >    2210             if word.capitalize() == word:
    > -> 2211                 result[index] = result[index].capitalize()
    >    2212             if word == word.upper():
    >    2213                 result[index] = result[index].upper()
    

    IndexError: list index out of range

    stale invalid 
    opened by uriva 9
  • Cannot install with old setuptools

    Cannot install with old setuptools

    Windows 7 Python 2.7.8

    C:\stufftodelete>pip install -e git+https://github.com/pwdyson/inflect.py#egg=inflect
    Obtaining inflect from git+https://github.com/pwdyson/inflect.py#egg=inflect
      Cloning https://github.com/pwdyson/inflect.py to c:\stufftodelete\src\inflect
      Running setup.py (path:C:\stufftodelete\src\inflect\setup.py) egg_info for package inflect
        usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
           or: -c --help [cmd1 cmd2 ...]
           or: -c --help-commands
           or: -c cmd --help
    
        error: invalid command 'egg_info'
        Complete output from command python setup.py egg_info:
        usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
    
       or: -c --help [cmd1 cmd2 ...]
    
       or: -c --help-commands
    
       or: -c cmd --help
    
    
    
    error: invalid command 'egg_info'
    
    ----------------------------------------
    Cleaning up...
    Command python setup.py egg_info failed with error code 1 in C:\stufftodelete\src\inflect
    

    But then:

    C:\stufftodelete>pip install --upgrade setuptools
    Downloading/unpacking setuptools from https://pypi.python.org/packages/3.4/s/setuptools/setuptools-7.0-py2.py3-none-any.
    whl#md5=918e7e5ea108507e1ffbbdfccc3496b1
    Installing collected packages: setuptools
      Found existing installation: setuptools 0.6c11
        Uninstalling setuptools:
          Successfully uninstalled setuptools
    Successfully installed setuptools
    Cleaning up...
    

    And so:

    C:\stufftodelete>pip install -e git+https://github.com/pwdyson/inflect.py#egg=inflect
    Obtaining inflect from git+https://github.com/pwdyson/inflect.py#egg=inflect
      Updating c:\stufftodelete\src\inflect clone
      Running setup.py (path:C:\stufftodelete\src\inflect\setup.py) egg_info for package inflect
    
      Installing extra requirements: 'egg'
    Installing collected packages: inflect
      Running setup.py develop for inflect
    
        Creating c:\python27\lib\site-packages\inflect.egg-link (link to .)
        Adding inflect 0.2.5pre1 to easy-install.pth file
    
        Installed c:\stufftodelete\src\inflect
    Successfully installed inflect
    Cleaning up...
    

    Can the dependency to certain setuptools version be included in the setup, or must it already be in place? If not, can it be mentioned in the README installation instructions?

    opened by hugovk 9
  • Failed to import: `Field` default cannot be set in `Annotated` for 'num_Annotated[str, FieldInfo(min_length=1, extra={})]'

    Failed to import: `Field` default cannot be set in `Annotated` for 'num_Annotated[str, FieldInfo(min_length=1, extra={})]'

    Error message:

    Traceback (most recent call last):
      File "/data/cuih7/[REDACTED]", line 7, in <module>
        import inflect
      File "/data/cuih7/miniconda3/envs/nlp20220817/lib/python3.10/site-packages/inflect/__init__.py", line 2046, in <module>
        class engine:
      File "/data/cuih7/miniconda3/envs/nlp20220817/lib/python3.10/site-packages/inflect/__init__.py", line 3781, in engine
        def number_to_words(  # noqa: C901
      File "pydantic/decorator.py", line 36, in pydantic.decorator.validate_arguments.validate
        import sys
      File "pydantic/decorator.py", line 126, in pydantic.decorator.ValidatedFunction.__init__
        try:
      File "pydantic/decorator.py", line 259, in pydantic.decorator.ValidatedFunction.create_model
        return fun
      File "pydantic/main.py", line 972, in pydantic.main.create_model
      File "pydantic/main.py", line 204, in pydantic.main.ModelMetaclass.__new__
      File "pydantic/fields.py", line 488, in pydantic.fields.ModelField.infer
      File "pydantic/fields.py", line 419, in pydantic.fields.ModelField.__init__
      File "pydantic/fields.py", line 534, in pydantic.fields.ModelField.prepare
      File "pydantic/fields.py", line 633, in pydantic.fields.ModelField._type_analysis
      File "pydantic/fields.py", line 776, in pydantic.fields.ModelField._create_sub_type
      File "pydantic/fields.py", line 451, in pydantic.fields.ModelField._get_field_info
    ValueError: `Field` default cannot be set in `Annotated` for 'num_Annotated[str, FieldInfo(min_length=1, extra={})]'
    

    I'm using the library from conda-forge. Downgrading from 6.0.0-pyhd8ed1ab_0 to 5.6.2-pyhd8ed1ab_0 fixes the issue.

    bug 
    opened by cuihaoleo 7
  • dash and lowered_split fix for inflect.py _plnoun()

    dash and lowered_split fix for inflect.py _plnoun()

    In function _plnoun(), the variable lowered_split is split on dashes, but when reusing this variable, code required whitespace split lowerd words, not dash split.

    opened by picobyte 7
  • Import unicode_literals from __futures__ for unicode handling in 2.7

    Import unicode_literals from __futures__ for unicode handling in 2.7

    Unicode strings would cause errors in python 2.7 when using inflect. With this one additional line, no error is thrown.

    Fixes #52

    Includes test file, testing for words containing unicode characters.

    opened by nielstron 7
  • Drop unsupported Python 3.3

    Drop unsupported Python 3.3

    EOL since 2017-09-29: https://en.wikipedia.org/wiki/CPython#Version_history

    See also https://github.com/pwdyson/inflect.py/pull/44 which fixes the flake8 error for Python 3.5 on the CI.

    opened by hugovk 7
  • "Entity" gets pluralized to "Entitys"

    docker run -it python:3.11 bash
    [email protected]:/# pip install inflect==6.0.2
    Collecting inflect==6.0.2
      Downloading inflect-6.0.2-py3-none-any.whl (34 kB)
    Collecting pydantic>=1.9.1
      Downloading pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (14.1 MB)
         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.1/14.1 MB 9.7 MB/s eta 0:00:00
    Collecting typing-extensions>=4.1.0
      Downloading typing_extensions-4.4.0-py3-none-any.whl (26 kB)
    Installing collected packages: typing-extensions, pydantic, inflect
    Successfully installed inflect-6.0.2 pydantic-1.10.2 typing-extensions-4.4.0
    WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
    [email protected]:/# python
    Python 3.11.1 (main, Dec 21 2022, 18:32:57) [GCC 10.2.1 20210110] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import inflect
    >>> word="Entity"
    >>> print(f'The plural of "{word}" is "{inflect.engine().plural(word)}".')
    The plural of "Entity" is "Entitys".
    >>> print(f'The plural of "{word}" is "{inflect.engine().plural_noun(word)}".')
    The plural of "Entity" is "Entitys".
    
    opened by fezzik1620 2
  • 'defnoun' doesn't seem to work when the word is a part of a string passed

    'defnoun' doesn't seem to work when the word is a part of a string passed

    Originally reported by @aMiss-aWry in #161:

    I can fix the specific words with defnoun('jeans', 'jeans'), which corrects the result for an isolated string 'jeans' -> 'jeans'.

    However, if I try to run plural_noun on 'blue jeans' instead of 'jeans' it then breaks again, returning 'blue jeanss'. I understand this is because 'blue jeans' appears to be a different string from 'jeans', but perhaps it should check the rules for the part of the string it is altering?

    feature help wanted 
    opened by jaraco 1
  • Words ending in 's' should never be pluralized by adding another 's'

    Words ending in 's' should never be pluralized by adding another 's'

    stockings -> stockingss jeans -> jeanss sandals -> sandalss

    How do I avoid this? I can fix the specific words with defnoun('jeans', 'jeans'), which corrects the result for an isolated string 'jeans' -> 'jeans'.

    However, if I try to run plural_noun on 'blue jeans' instead of 'jeans' it then breaks again, returning 'blue jeanss'. I understand this is because 'blue jeans' appears to be a different string from 'jeans', but perhaps it should check the rules for the part of the string it is altering?

    I've gotten around this so far by this incredibly hacky 'solution', so any improvement would obviously be immensely appreciated:

                plural = _INFLECT.plural_noun(key, count)
                if plural.endswith('ss'):
                    plural = plural[0:-1]
    
    feature help wanted 
    opened by aMiss-aWry 4
  • singular_noun on word ending in

    singular_noun on word ending in "s" removes s.

    
    import inflect as Inflect
    inflect = Inflect.engine()
    inflect.singular_noun("car")           # get False, as expected
    inflect.singular_noun("mass")          # get "mas", expected False
    
    

    Is this behavior a bug? singular_noun() is supposed to return False when the word is already singular, and I can find no reference to suggest "mass" is the plural of "mas", which is itself the plural of "ma".

    help wanted 
    opened by eykamp 3
Releases(v6.0.2)
Code for the paper "A Simple but Tough-to-Beat Baseline for Sentence Embeddings".

Code for the paper "A Simple but Tough-to-Beat Baseline for Sentence Embeddings".

1.1k Dec 27, 2022
Using context-free grammar formalism to parse English sentences to determine their structure to help computer to better understand the meaning of the sentence.

Sentance Parser Executing the Program Make sure Python 3.6+ is installed. Install requirements $ pip install requirements.txt Run the program:

Vaibhaw 12 Sep 28, 2022
💫 Industrial-strength Natural Language Processing (NLP) in Python

spaCy: Industrial-strength NLP spaCy is a library for advanced Natural Language Processing in Python and Cython. It's built on the very latest researc

Explosion 24.9k Jan 02, 2023
Multi Task Vision and Language

12-in-1: Multi-Task Vision and Language Representation Learning Please cite the following if you use this code. Code and pre-trained models for 12-in-

Meta Research 711 Jan 08, 2023
Code for EMNLP20 paper: "ProphetNet: Predicting Future N-gram for Sequence-to-Sequence Pre-training"

ProphetNet-X This repo provides the code for reproducing the experiments in ProphetNet. In the paper, we propose a new pre-trained language model call

Microsoft 394 Dec 17, 2022
Part of Speech Tagging using Hidden Markov Model (HMM) POS Tagger and Brill Tagger

Part of Speech Tagging using Hidden Markov Model (HMM) POS Tagger and Brill Tagger In this project, our aim is to tune, compare, and contrast the perf

Chirag Daryani 0 Dec 25, 2021
Build Text Rerankers with Deep Language Models

Reranker is a lightweight, effective and efficient package for training and deploying deep languge model reranker in information retrieval (IR), question answering (QA) and many other natural languag

Luyu Gao 140 Dec 06, 2022
A PyTorch implementation of VIOLET

VIOLET: End-to-End Video-Language Transformers with Masked Visual-token Modeling A PyTorch implementation of VIOLET Overview VIOLET is an implementati

Tsu-Jui Fu 119 Dec 30, 2022
BERT, LDA, and TFIDF based keyword extraction in Python

BERT, LDA, and TFIDF based keyword extraction in Python kwx is a toolkit for multilingual keyword extraction based on Google's BERT and Latent Dirichl

Andrew Tavis McAllister 41 Dec 27, 2022
中文生成式预训练模型

T5 PEGASUS 中文生成式预训练模型,以mT5为基础架构和初始权重,通过类似PEGASUS的方式进行预训练。 详情可见:https://kexue.fm/archives/8209 Tokenizer 我们将T5 PEGASUS的Tokenizer换成了BERT的Tokenizer,它对中文更

410 Jan 03, 2023
Integrating the Best of TF into PyTorch, for Machine Learning, Natural Language Processing, and Text Generation. This is part of the CASL project: http://casl-project.ai/

Texar-PyTorch is a toolkit aiming to support a broad set of machine learning, especially natural language processing and text generation tasks. Texar

ASYML 726 Dec 30, 2022
Application to help find best train itinerary, uses speech to text, has a spam filter to segregate invalid inputs, NLP and Pathfinding algos.

T-IAI-901-MSC2022 - GROUP 18 Gestion de projet Notre travail a été organisé et réparti dans un Trello. https://trello.com/b/X3s2fpPJ/ia-projet Install

1 Feb 05, 2022
숭실대학교 컴퓨터학부 전공종합설계프로젝트

✨ 시각장애인을 위한 버스도착 알림 장치 ✨ 👀 개요 현대 사회에서 대중교통 위치 정보를 이용하여 사람들이 간단하게 이용할 대중교통의 정보를 얻고 쉽게 대중교통을 이용할 수 있다. 해당 정보는 각종 어플리케이션과 대중교통 이용시설에서 위치 정보를 제공하고 있지만 시각

taegyun 3 Jan 25, 2022
Code for hyperboloid embeddings for knowledge graph entities

Implementation for the papers: Self-Supervised Hyperboloid Representations from Logical Queries over Knowledge Graphs, Nurendra Choudhary, Nikhil Rao,

30 Dec 10, 2022
Pretrained Japanese BERT models

Pretrained Japanese BERT models This is a repository of pretrained Japanese BERT models. The models are available in Transformers by Hugging Face. Mod

Inui Laboratory 387 Dec 30, 2022
Open source annotation tool for machine learning practitioners.

doccano doccano is an open source text annotation tool for humans. It provides annotation features for text classification, sequence labeling and sequ

7.1k Jan 01, 2023
A Domain Specific Language (DSL) for building language patterns. These can be later compiled into spaCy patterns, pure regex, or any other format

RITA DSL This is a language, loosely based on language Apache UIMA RUTA, focused on writing manual language rules, which compiles into either spaCy co

Šarūnas Navickas 60 Sep 26, 2022
Signature remover is a NLP based solution which removes email signatures from the rest of the text.

Signature Remover Signature remover is a NLP based solution which removes email signatures from the rest of the text. It helps to enchance data conten

Forges Alterway 8 Jan 06, 2023
APEACH: Attacking Pejorative Expressions with Analysis on Crowd-generated Hate Speech Evaluation Datasets

APEACH - Korean Hate Speech Evaluation Datasets APEACH is the first crowd-generated Korean evaluation dataset for hate speech detection. Sentences of

Kevin-Yang 70 Dec 06, 2022
Turkish Stop Words Türkçe Dolgu Sözcükleri

trstop Turkish Stop Words Türkçe Dolgu Sözcükleri In this repository I put Turkish stop words that is contained in the first 10 thousand words with th

Ahmet Aksoy 103 Nov 12, 2022