Подтвердить что ты не робот

Замена нормальных номеров

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

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

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

4b9b3361

Ответ 1

Здесь крошечное решение, взятое из Gareth on 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])

Ответ 2

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

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

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

Ответ 3

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

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']

Ответ 4

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

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

Для чисел более 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" для удобства использования и может быть вызван путем импорта имени файла, которое я назвал "порядковым", по порядку импорта, а затем по порядку. (номер).

Дайте мне знать, что вы думаете: D

Ответ 5

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

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

>>> 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 в обеих этих функциях и создать свой собственный код, чтобы сделать это динамически (я не пытался это сделать).

Ответ 6

Если вы не хотите получать дополнительную зависимость от внешней библиотеки (как это было предложено 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

Ответ 7

Другое решение - библиотека 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'

Ответ 8

эта функция хорошо работает для каждого числа n. Если n отрицательно, оно преобразуется в положительное. Если n не целое, оно преобразуется в целое.

def ordinal( n ):

    suffix = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th']

    if n < 0:
        n *= -1

    n = int(n)

    if n % 100 in (11,12,13):
        s = 'th'
    else:
        s = suffix[n % 10]

    return str(n) + s

Ответ 9

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

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

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

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

Ответ 10

Если вы не хотите импортировать внешний модуль и предпочитаете однострочное решение, то, вероятно, (чуть-чуть) более читаемый, чем принятый ответ:

def suffix(i):
    return {1:"st", 2:"nd", 3:"rd"}.get(i%10*(i%100 not in [11,12,13]), "th"))

Он использует словарь .get, как предлагается https://codereview.stackexchange.com/a/41300/90593 и fooobar.com/questions/200047/....

Я использовал умножение с булевым для обработки особых случаев (11,12,13) ​​без необходимости запуска if-блока. Если условие (i%100 not in [11,12,13]) оценивается как False, целое число равно 0, и мы получаем случай по умолчанию "th".

Ответ 11

Это может обработать любое число длины, исключения для... # 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() была доступна без явного включения математического модуля.

Ответ 12

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

>>> from num2words import num2words
>>> num2words(42, to='ordinal_num')
    '42nd'

Ответ 13

Попробуй это

import sys

a = int(sys.argv[1])

for i in range(1,a+1):

j = i
if(j%100 == 11 or j%100 == 12 or j%100 == 13):
    print("%dth Hello"%(j))
    continue            
i %= 10
if ((j%10 == 1) and ((i%10 != 0) or (i%10 != 1))):
    print("%dst Hello"%(j))
elif ((j%10 == 2) and ((i%10 != 0) or (i%10 != 1))):
    print("%dnd Hello"%(j))
elif ((j%10 == 3) and ((i%10 != 0) or (i%10 != 1))):
    print("%drd Hello"%(j))
else:
    print("%dth Hello"%(j))

Ответ 14

Вот более сложное решение, которое я только что написал, что учитывает составленные ординалы. Таким образом, он работает от first до nine hundred and ninety ninth. Мне нужно было преобразовать имена строковых улиц в порядковые номера чисел:

import re
from collections import OrderedDict

ONETHS = {
    'first': '1ST', 'second': '2ND', 'third': '3RD', 'fourth': '4TH', 'fifth': '5TH', 'sixth': '6TH', 'seventh': '7TH',
    'eighth': '8TH', 'ninth': '9TH'
}

TEENTHS = {
    'tenth': '10TH', 'eleventh': '11TH', 'twelfth': '12TH', 'thirteenth': '13TH',
    'fourteenth': '14TH', 'fifteenth': '15TH', 'sixteenth': '16TH', 'seventeenth': '17TH', 'eighteenth': '18TH',
    'nineteenth': '19TH'
}

TENTHS = {
    'twentieth': '20TH', 'thirtieth': '30TH', 'fortieth': '40TH', 'fiftieth': '50TH', 'sixtieth': '60TH',
    'seventieth': '70TH', 'eightieth': '80TH', 'ninetieth': '90TH',
}

HUNDREDTH = {'hundredth': '100TH'}  # HUNDREDTH not s

ONES = {'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5', 'six': '6', 'seven': '7', 'eight': '8',
        'nine': '9'}

TENS = {'twenty': '20', 'thirty': '30', 'forty': '40', 'fifty': '50', 'sixty': '60', 'seventy': '70', 'eighty': '80',
        'ninety': '90'}

HUNDRED = {'hundred': '100'}

# Used below for ALL_ORDINALS
ALL_THS = {}
ALL_THS.update(ONETHS)
ALL_THS.update(TEENTHS)
ALL_THS.update(TENTHS)
ALL_THS.update(HUNDREDTH)

ALL_ORDINALS = OrderedDict()
ALL_ORDINALS.update(ALL_THS)
ALL_ORDINALS.update(TENS)
ALL_ORDINALS.update(HUNDRED)
ALL_ORDINALS.update(ONES)


def split_ordinal_word(word):
    ordinals = []
    if not word:
        return ordinals 

    for key, value in ALL_ORDINALS.items():
        if word.startswith(key):
            ordinals.append(key)
            ordinals += split_ordinal_word(word[len(key):])
            break
    return ordinals

def get_ordinals(s):
    ordinals, start, end = [], [], []
    s = s.strip().replace('-', ' ').replace('and', '').lower()
    s = re.sub(' +',' ', s)  # Replace multiple spaces with a single space
    s = s.split(' ')

    for word in s:
        found_ordinals = split_ordinal_word(word)
        if found_ordinals:
            ordinals += found_ordinals
        else:  # else if word, for covering blanks
            if ordinals:  # Already have some ordinals
                end.append(word)
            else:
                start.append(word)
    return start, ordinals, end


def detect_ordinal_pattern(ordinals):
    ordinal_length = len(ordinals)
    ordinal_string = '' # ' '.join(ordinals)
    if ordinal_length == 1:
        ordinal_string = ALL_ORDINALS[ordinals[0]]
    elif ordinal_length == 2:
        if ordinals[0] in ONES.keys() and ordinals[1] in HUNDREDTH.keys():
            ordinal_string = ONES[ordinals[0]] + '00TH'
        elif ordinals[0] in HUNDRED.keys() and ordinals[1] in ONETHS.keys():
            ordinal_string = HUNDRED[ordinals[0]][:-1] + ONETHS[ordinals[1]]
        elif ordinals[0] in TENS.keys() and ordinals[1] in ONETHS.keys():
            ordinal_string = TENS[ordinals[0]][0] + ONETHS[ordinals[1]]
    elif ordinal_length == 3:
        if ordinals[0] in HUNDRED.keys() and ordinals[1] in TENS.keys() and ordinals[2] in ONETHS.keys():
            ordinal_string = HUNDRED[ordinals[0]][0] + TENS[ordinals[1]][0] + ONETHS[ordinals[2]]
        elif ordinals[0] in ONES.keys() and ordinals[1] in HUNDRED.keys() and ordinals[2] in ALL_THS.keys():
            ordinal_string =  ONES[ordinals[0]] + ALL_THS[ordinals[2]]
    elif ordinal_length == 4:
        if ordinals[0] in ONES.keys() and ordinals[1] in HUNDRED.keys() and ordinals[2] in TENS.keys() and \
           ordinals[3] in ONETHS.keys():
                ordinal_string = ONES[ordinals[0]] + TENS[ordinals[2]][0] + ONETHS[ordinals[3]]

    return ordinal_string

И вот несколько примеров использования:

# s = '32 one   hundred and forty-third st toronto, on'
#s = '32 forty-third st toronto, on'
#s = '32 one-hundredth st toronto, on'
#s = '32 hundred and third st toronto, on'
#s = '32 hundred and thirty first st toronto, on'
# s = '32 nine hundred and twenty third st toronto, on'
#s = '32 nine hundred and ninety ninth st toronto, on'
s = '32 sixty sixth toronto, on'

st, ords, en = get_ordinals(s)
print st, detect_ordinal_pattern(ords), en

Ответ 15

Я приветствую лямбда-код Гарета. Так элегантно. Я лишь наполовину понимаю, как это работает. Поэтому я попытался разобрать его и придумал следующее:

def ordinal(integer):

    int_to_string = str(integer)

    if int_to_string == '1' or int_to_string == '-1':
        print int_to_string+'st'
        return int_to_string+'st';
    elif int_to_string == '2' or int_to_string == '-2':
        print int_to_string+'nd'
        return int_to_string+'nd';
    elif int_to_string == '3' or int_to_string == '-3':
        print int_to_string+'rd'
        return int_to_string+'rd';

    elif int_to_string[-1] == '1' and int_to_string[-2] != '1':
        print int_to_string+'st'
        return int_to_string+'st';
    elif int_to_string[-1] == '2' and int_to_string[-2] != '1':
        print int_to_string+'nd'
        return int_to_string+'nd';
    elif int_to_string[-1] == '3' and int_to_string[-2] != '1':
        print int_to_string+'rd'
        return int_to_string+'rd';

    else:
        print int_to_string+'th'
        return int_to_string+'th';


>>> print [ordinal(n) for n in range(1,25)]
1st
2nd
3rd
4th
5th
6th
7th
8th
9th
10th
11th
12th
13th
14th
15th
16th
17th
18th
19th
20th
21st
22nd
23rd
24th
['1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th', '9th', '10th',             
'11th', '12th', '13th', '14th', '15th', '16th', '17th', '18th', '19th', 
'20th', '21st', '22nd', '23rd', '24th']

Ответ 16

Код Gareth, выраженный с использованием современного .format()

ordinal = lambda n: "{}{}".format(n,"tsnrhtdd"[(n/10%10!=1)*(n%10<4)*n%10::4])

Ответ 17

Там есть порядковая функция в гуманизации

pip install humanize

>>> [(x, humanize.ordinal(x)) for x in (1, 2, 3, 4, 20, 21, 22, 23, 24, 100, 101,
...                                     102, 103, 113, -1, 0, 1.2, 13.6)]
[(1, '1st'), (2, '2nd'), (3, '3rd'), (4, '4th'), (20, '20th'), (21, '21st'),
 (22, '22nd'), (23, '23rd'), (24, '24th'), (100, '100th'), (101, '101st'),
 (102, '102nd'), (103, '103rd'), (113, '113th'), (-1, '-1th'), (0, '0th'),
 (1.2, '1st'), (13.6, '13th')]