web-dev-qa-db-ja.com

序数の置換

現在、1番目、2番目、3番目などの単語を適切な序数表現(1番目、2番目、3番目)に置き換える方法を探しています。私は先週グーグルで調べましたが、便利な標準ツールやNLTKの機能が見つかりませんでした。

手動で正規表現を作成する必要がありますか?

アドバイスをありがとう

40
skornos

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])
93
Ben Davis

これはどう:

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

前の質問 に対する受け入れられた答えには、この半分のアルゴリズムがあります:"first"1に変えます。そこから"1st"に移動するには、次のようにします。

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

これは、数字の0〜19でのみ機能します。

7
lvc

私は私のプロジェクトに序数を使用したかったので、いくつかのプロトタイプを作成した後、このメソッドは小さくはないが、正の整数、はい整数で機能すると思います。

数値が20を上回るか下回るかを決定することにより機能し、数値が20を下回る場合、int 1をストリング1st、2、2ndに変換します。 3、3番目。残りには「st」が追加されます。

20を超える数の場合、最後の桁と2番目から最後の桁が必要になります。これらはそれぞれ10桁と1桁と呼ばれ、それらをテストして数値に何を追加するかを確認します。

これはpythonであるため、他の言語が文字列の最後の桁または最後から2番目の桁を見つけることができるかどうかはわかりません。

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」と呼ばれるファイル名をimport ordinal、次にordinal.o(number)でインポートすることで呼び出すことができます。

あなたの考えを教えてください:D

6
Houngan

序数のアドレス(「Third St」)をジオコーダーが理解できる形式(「3rd St」)に変換する必要があるため、同様のことをしていることに気付きました。これは非常にエレガントではありませんが、迅速で汚い解決策の1つは inflect.py を使用して翻訳用の辞書を生成することです。

inflect.pyにはnumber_to_words()関数があり、数値(例__2_)をWord形式(例__'two'_)に変換します。さらに、ordinal()関数があり、任意の数(数字またはWord形式)を取り、それを通常の形式に変換します(例_4_-> fourthsix-> 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の内部動作を調べて、これを動的に実行するための独自のコードを構築することができます(これを試していません)。

6
alukach

別の解決策はnum2wordsライブラリ( pip | github )です。特に異なる言語を提供するため、ローカリゼーション/国際化(別名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'
4
luckydonald

外部ライブラリへの追加の依存関係を取得したくない場合( luckydonaldが推奨golfed code production)を使用した場合、ここに短いが保守可能なバリアントがあります。

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
Florian Brucker

Djangoを使用している場合、次のことができます。

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

(またはDjangoテンプレートを意図したテンプレートフィルターとして使用しますが、pythonコードでも同様に機能します)

Djangoを使用しない場合は、盗むことができます その実装 これは非常にきれいです。

3
Monika Sulik

これを試して

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))
1

これは、num2wordsパッケージを使用する代替オプションです。

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

外部モジュールをインポートせず、1行のソリューションを希望する場合は、受け入れられた回答よりもおそらく(少し)読みやすくなります。

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

https://codereview.stackexchange.com/a/41300/9059 および https://stackoverflow.com/a/36977549で示唆されているように、辞書.getを使用します。/5069869

Ifブロックを開始することなく、特殊なケース(11、12、13)を処理するためにブール値を乗算しました。条件(i%100 not in [11,12,13])Falseと評価される場合、整数は0であり、デフォルトの 'th'ケースが取得されます。

1
Bernhard

これは、任意の長さの数値、...#11〜...#13の例外、および負の整数を処理できます。

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

組み込みのord()をオーバーライドしないように、名前としてith()を使用することをお勧めします。

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

注:Python 3.6;でテスト済み。abs()関数は、数学モジュールを明示的に含めることなく使用できました。

1
Amp Balfour

この関数は、各番号に対して適切に機能しますnnが負の場合、正に変換されます。 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
1
Dario Z.

複雑な序数を考慮に入れた、先ほど書いたより複雑なソリューションを次に示します。したがって、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
0
radtek

最新の.format()を使用して表現されたGarethのコード

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

Garethのラムダコードに敬意を表します。とてもエレガント。私はそれがどのように機能するかを半分しか理解していません。だから私はそれを分解しようとし、これを思いついた:

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

hum​​anize には順序関数があります

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

0
timdiels