mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Merge pull request #2925 from InspectorCaracal/str2int
Add `str2int` as counterpart to `int2str`
This commit is contained in:
commit
01e33751d8
2 changed files with 117 additions and 0 deletions
|
|
@ -696,3 +696,36 @@ class TestDelay(BaseEvenniaTest):
|
|||
timedelay
|
||||
) # Clock must advance to trigger, even if past timedelay
|
||||
self.assertEqual(self.char1.ndb.dummy_var, "dummy_func ran")
|
||||
|
||||
|
||||
class TestIntConversions(TestCase):
|
||||
def test_int2str(self):
|
||||
self.assertEqual("three", utils.int2str(3))
|
||||
# special adjective conversion
|
||||
self.assertEqual("3rd", utils.int2str(3, adjective=True))
|
||||
# generic adjective conversion
|
||||
self.assertEqual("5th", utils.int2str(5, adjective=True))
|
||||
# No mapping return int as str
|
||||
self.assertEqual("15", utils.int2str(15))
|
||||
|
||||
def test_str2int(self):
|
||||
# simple conversions
|
||||
self.assertEqual(5, utils.str2int("5"))
|
||||
|
||||
# basic mapped numbers
|
||||
self.assertEqual(3, utils.str2int("three"))
|
||||
self.assertEqual(20, utils.str2int("twenty"))
|
||||
|
||||
# multi-place numbers
|
||||
self.assertEqual(2345, utils.str2int("two thousand, three hundred and forty-five"))
|
||||
|
||||
# ordinal numbers
|
||||
self.assertEqual(1, utils.str2int("1st"))
|
||||
self.assertEqual(1, utils.str2int("first"))
|
||||
self.assertEqual(4, utils.str2int("fourth"))
|
||||
# ordinal sound-change conversions
|
||||
self.assertEqual(5, utils.str2int("fifth"))
|
||||
self.assertEqual(20, utils.str2int("twentieth"))
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
utils.str2int("not a number")
|
||||
|
|
@ -2755,3 +2755,87 @@ def int2str(number, adjective=False):
|
|||
if adjective:
|
||||
return _INT2STR_MAP_ADJ.get(number, f"{number}th")
|
||||
return _INT2STR_MAP_NOUN.get(number, str(number))
|
||||
|
||||
_STR2INT_MAP = {
|
||||
"one": 1, "two": 2, "three": 3,
|
||||
"four": 4, "five": 5, "six": 6,
|
||||
"seven": 7, "eight": 8, "nine": 9,
|
||||
"ten": 10, "eleven": 11, "twelve": 12,
|
||||
"thirteen": 13, "fourteen": 14, "fifteen": 15,
|
||||
"sixteen": 16, "seventeen": 17, "eighteen": 18,
|
||||
"nineteen": 19, "twenty": 20, "thirty": 30,
|
||||
"forty": 40, "fifty": 50, "sixty": 60,
|
||||
"seventy": 70, "eighty": 80, "ninety": 90,
|
||||
"hundred": 100, "thousand": 1000,
|
||||
}
|
||||
_STR2INT_ADJS = {
|
||||
"first": 1, "second": 2, "third": 3,
|
||||
}
|
||||
def str2int(number):
|
||||
"""
|
||||
Converts a string to an integer.
|
||||
|
||||
Args:
|
||||
number (str): The string to convert. It can be a digit such as "1", or a number word such as "one".
|
||||
|
||||
Returns:
|
||||
int: The string represented as an integer.
|
||||
"""
|
||||
number = str(number)
|
||||
original_input = number
|
||||
try:
|
||||
# it's a digit already
|
||||
return int(number)
|
||||
except:
|
||||
# if it's an ordinal number such as "1st", it'll convert to int with the last two characters chopped off
|
||||
try:
|
||||
return int(number[:-2])
|
||||
except:
|
||||
pass
|
||||
|
||||
# convert sound changes for generic ordinal numbers
|
||||
if number[-2:] == "th":
|
||||
# remove "th"
|
||||
number = number[:-2]
|
||||
if number[-1] == "f":
|
||||
# e.g. twelfth, fifth
|
||||
number = number[:-1] + "ve"
|
||||
elif number[-2:] == "ie":
|
||||
# e.g. twentieth, fortieth
|
||||
number = number[:-2] + "y"
|
||||
# custom case for ninth
|
||||
elif number[-3:] == "nin":
|
||||
number += "e"
|
||||
|
||||
if i := _STR2INT_MAP.get(number):
|
||||
# it's a single number, return it
|
||||
return i
|
||||
|
||||
# remove optional "and"s
|
||||
number = number.replace(" and "," ")
|
||||
|
||||
# split number words by spaces, hyphens and commas, to accommodate multiple styles
|
||||
numbers = [ word.lower() for word in re.split(r'[-\s\,]',number) if word ]
|
||||
sums = []
|
||||
for word in numbers:
|
||||
# check if it's a known number-word
|
||||
if i := _STR2INT_MAP.get(word):
|
||||
if not len(sums):
|
||||
# initialize the list with the current value
|
||||
sums = [i]
|
||||
else:
|
||||
# if the previous number was smaller, it's a multiplier
|
||||
# e.g. the "two" in "two hundred"
|
||||
if sums[-1] < i:
|
||||
sums[-1] = sums[-1]*i
|
||||
# otherwise, it's added on, like the "five" in "twenty five"
|
||||
else:
|
||||
sums.append(i)
|
||||
elif i := _STR2INT_ADJS.get(word):
|
||||
# it's a special adj word; ordinal case will never be a multiplier
|
||||
sums.append(i)
|
||||
else:
|
||||
# invalid number-word, raise ValueError
|
||||
raise ValueError(f"String {original_input} cannot be converted to int.")
|
||||
return sum(sums)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue