現在、1番目、2番目、3番目などの単語を適切な序数表現(1番目、2番目、3番目)に置き換える方法を探しています。私は先週グーグルで調べましたが、便利な標準ツールやNLTKの機能が見つかりませんでした。
手動で正規表現を作成する必要がありますか?
アドバイスをありがとう
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])
これはどう:
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']
前の質問 に対する受け入れられた答えには、この半分のアルゴリズムがあります:"first"
を1
に変えます。そこから"1st"
に移動するには、次のようにします。
suffixes = ["th", "st", "nd", "rd", ] + ["th"] * 16
suffixed_num = str(num) + suffixes[num % 100]
これは、数字の0〜19でのみ機能します。
私は私のプロジェクトに序数を使用したかったので、いくつかのプロトタイプを作成した後、このメソッドは小さくはないが、正の整数、はい整数で機能すると思います。
数値が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
序数のアドレス(「Third St」)をジオコーダーが理解できる形式(「3rd St」)に変換する必要があるため、同様のことをしていることに気付きました。これは非常にエレガントではありませんが、迅速で汚い解決策の1つは inflect.py を使用して翻訳用の辞書を生成することです。
inflect.pyにはnumber_to_words()
関数があり、数値(例__2
_)をWord形式(例__'two'
_)に変換します。さらに、ordinal()
関数があり、任意の数(数字またはWord形式)を取り、それを通常の形式に変換します(例_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の内部動作を調べて、これを動的に実行するための独自のコードを構築することができます(これを試していません)。
別の解決策は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'
外部ライブラリへの追加の依存関係を取得したくない場合( 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
Djangoを使用している場合、次のことができます。
from Django.contrib.humanize.templatetags.humanize import ordinal
var = ordinal(number)
(またはDjangoテンプレートを意図したテンプレートフィルターとして使用しますが、pythonコードでも同様に機能します)
Djangoを使用しない場合は、盗むことができます その実装 これは非常にきれいです。
これを試して
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))
これは、num2wordsパッケージを使用する代替オプションです。
>>> from num2words import num2words
>>> num2words(42, to='ordinal_num')
'42nd'
外部モジュールをインポートせず、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'ケースが取得されます。
これは、任意の長さの数値、...#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()関数は、数学モジュールを明示的に含めることなく使用できました。
この関数は、各番号に対して適切に機能します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
複雑な序数を考慮に入れた、先ほど書いたより複雑なソリューションを次に示します。したがって、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
最新の.format()を使用して表現されたGarethのコード
ordinal = lambda n: "{}{}".format(n,"tsnrhtdd"[(n/10%10!=1)*(n%10<4)*n%10::4])
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']
humanize には順序関数があります
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')]