Замена порядковых номеров - PullRequest
38 голосов
/ 10 марта 2012

В настоящее время я ищу способ заменить слова, такие как первое, второе, третье, ... соответствующим представлением порядкового номера (1, 2, 3). Я гуглил на прошлой неделе, и я не нашел ни одного полезного стандартного инструмента или какой-либо функции от NLTK.

Так есть ли или я должен написать некоторые регулярные выражения вручную?

Спасибо за любой совет

Ответы [ 17 ]

90 голосов
/ 15 ноября 2013

Вот краткое решение, взятое из Гарет на Codegolf :

ordinal = lambda n: "%d%s" % (n,"tsnrhtdd"[(n/10%10!=1)*(n%10<4)*n%10::4])

Работает на любой номер:

print([ordinal(n) for n in range(1,32)])

['1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th', '9th', '10th',
 '11th', '12th', '13th', '14th', '15th', '16th', '17th', '18th', '19th',
 '20th', '21st', '22nd', '23rd', '24th', '25th', '26th', '27th', '28th',
 '29th', '30th', '31st']

Для Python 3.4+, math.floor необходимо:

import math
ordinal = lambda n: "%d%s" % (n,"tsnrhtdd"[(math.floor(n/10)%10!=1)*(n%10<4)*n%10::4])
9 голосов
/ 02 мая 2016

Как насчет этого:

suf = lambda n: "%d%s"%(n,{1:"st",2:"nd",3:"rd"}.get(n if n<20 else n%10,"th"))
print [suf(n) for n in xrange(1,32)]

['1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th', '9th', '10th',
 '11th', '12th', '13th', '14th', '15th', '16th', '17th', '18th', '19th',
 '20th', '21st', '22nd', '23rd', '24th', '25th', '26th', '27th', '28th',
 '29th', '30th', '31st']
7 голосов
/ 10 марта 2012

Принятый ответ на предыдущий вопрос имеет алгоритм для половины этого: он превращает "first" в 1.Чтобы перейти оттуда к "1st", сделайте что-то вроде:

suffixes = ["th", "st", "nd", "rd", ] + ["th"] * 16
suffixed_num = str(num) + suffixes[num % 100]

Это работает только для чисел 0-19.

6 голосов
/ 07 сентября 2013

Я хотел использовать ординалы для моего проекта, и после нескольких прототипов я думаю, что этот метод, хотя и не маленький, будет работать для любого натурального числа, да любое целое число .

Это работаетопределив, является ли число выше или ниже 20, если число меньше 20, оно превратит int 1 в строку 1st, 2, 2nd;3, 3;а остальные добавят к нему "st".

Для чисел старше 20 потребуется последняя и вторая до последней цифры, которые я назвал десятками и единицами соответственно, и проверим их, чтобы увидеть, что добавить к числу.

Кстати, это на python, поэтому я не уверен, смогут ли другие языки найти последнюю или последнюю или последнюю цифру в строке, если они это сделают, это должно довольно легко перевести.

def o(numb):
    if numb < 20: #determining suffix for < 20
        if numb == 1: 
            suffix = 'st'
        elif numb == 2:
            suffix = 'nd'
        elif numb == 3:
            suffix = 'rd'
        else:
            suffix = 'th'  
    else:   #determining suffix for > 20
        tens = str(numb)
        tens = tens[-2]
        unit = str(numb)
        unit = unit[-1]
        if tens == "1":
           suffix = "th"
        else:
            if unit == "1": 
                suffix = 'st'
            elif unit == "2":
                suffix = 'nd'
            elif unit == "3":
                suffix = 'rd'
            else:
                suffix = 'th'
    return str(numb)+ suffix

Я вызвал функцию "o" для простоты использования и может быть вызван путем импорта имени файла, которое я назвал "ordinal", путем импорта ordinal, а затем ordinal.o (число).

Пустья знаю, что вы думаете: D

6 голосов
/ 10 февраля 2014

Я обнаружил, что делаю что-то похожее, мне нужно преобразовать адреса с порядковыми номерами ('Third St') в формат, который может понять геокодер ('3rd St'). Хотя это не очень элегантно, одним из быстрых и грязных решений является использование inflect.py для создания словаря для перевода.

inflect.py имеет функцию number_to_words(), которая преобразует число (например, 2) в его словесную форму (например, 'two'). Кроме того, есть функция ordinal(), которая будет принимать любое число (цифру или слово) и превращать его в порядковый номер (например, 4 -> fourth, six -> sixth). Ни один из них сам по себе не делает то, что вы ищете, но вместе вы можете использовать их для создания словаря, чтобы перевести любое предоставленное слово порядкового номера (в разумных пределах) в соответствующий числовой порядковый номер. Взгляните:

>>> import inflect
>>> p = inflect.engine()
>>> word_to_number_mapping = {}
>>>
>>> for i in range(1, 100):
...     word_form = p.number_to_words(i)  # 1 -> 'one'
...     ordinal_word = p.ordinal(word_form)  # 'one' -> 'first'
...     ordinal_number = p.ordinal(i)  # 1 -> '1st'
...     word_to_number_mapping[ordinal_word] = ordinal_number  # 'first': '1st'
...
>>> print word_to_number_mapping['sixth']
6th
>>> print word_to_number_mapping['eleventh']
11th
>>> print word_to_number_mapping['forty-third']
43rd

Если вы хотите выделить какое-то время, возможно, можно будет изучить внутреннюю работу inflect.py в обеих этих функциях и создать собственный код для этого динамически (я не пытался это делать).

4 голосов
/ 22 июня 2018

Если вы не хотите получать дополнительную зависимость от внешней библиотеки (как предложено luckydonald ), но также не хотите, чтобы будущий сопровождающий код преследовал вас и убивал вас(потому что вы использовали гольф-код в производстве), вот короткий, но обслуживаемый вариант:

def make_ordinal(n):
    '''
    Convert an integer into its ordinal representation::

        make_ordinal(0)   => '0th'
        make_ordinal(3)   => '3rd'
        make_ordinal(122) => '122nd'
        make_ordinal(213) => '213th'
    '''
    n = int(n)
    suffix = ['th', 'st', 'nd', 'rd', 'th'][min(n % 10, 4)]
    if 11 <= (n % 100) <= 13:
        suffix = 'th'
    return str(n) + suffix
4 голосов
/ 05 января 2018

Другим решением является библиотека num2words ( pip | github ). В частности, он предлагает разные языки, поэтому локализация / интернационализация (aka. L10n / i18n) не составляет труда.

Использовать легко после того, как вы установили его с pip install num2words:

from num2words import num2words
# english is default
num2words(4458, to="ordinal_num")
'4458rd'

# examples for other languages
num2words(4458, lang="en", to="ordinal_num")
'4458rd'

num2words(4458, lang="es", to="ordinal_num")
'4458º'

num2words(4458, lang="de", to="ordinal_num")
'4458.'

num2words(4458, lang="id", to="ordinal_num")
'ke-4458'

Бонус:

num2words(4458, lang="en", to="ordinal")
'four thousand, four hundred and fifty-eighth'
2 голосов
/ 21 июня 2017

Если вы используете django, вы можете сделать:

from django.contrib.humanize.templatetags.humanize import ordinal
var = ordinal(number)

(или использовать порядковый номер в шаблоне django в качестве фильтра шаблона, которым он должен был быть, хотя вызов его так из кода Python также работает)

Если вы не используете django, вы можете украсть их реализацию , что очень аккуратно.

1 голос
/ 21 мая 2018

Это альтернативные варианты, использующие пакет num2words.

>>> from num2words import num2words
>>> num2words(42, to='ordinal_num')
    '42nd'
1 голос
/ 15 мая 2018

Это может обработать любое число длины, исключения для ... # 11 до ... # 13 и отрицательные целые.

def ith(i):return(('th'*(10<(abs(i)%100)<14))+['st','nd','rd',*['th']*7][(abs(i)-1)%10])[0:2]

Я предлагаю использовать ith () в качестве имени, чтобы избежать переопределения встроенного ord ().

# test routine
for i in range(-200,200):
    print(i,ith(i))

Примечание: протестировано с Python 3.6; Функция abs () была доступна без явного включения математического модуля.

...