-
Notifications
You must be signed in to change notification settings - Fork 1
/
numberutils.py
146 lines (119 loc) · 4.16 KB
/
numberutils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import string
numeral_map = tuple(zip(
(1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1),
('M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I')
))
def int_to_roman(i):
"""
convert integer to roman number
:param i: integer
:return: roman number (string)
"""
result = []
for integer, numeral in numeral_map:
count = i // integer
result.append(numeral * count)
i -= integer * count
return ''.join(result)
def roman_to_int(n):
"""
convert roman number to integer
:param n: roman number (string)
:return: integer
"""
i = result = 0
for integer, numeral in numeral_map:
while n[i:i + len(numeral)] == numeral:
result += integer
i += len(numeral)
return result
_nums = ('', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight',
'Nine', 'Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen',
'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen')
_tens = ('Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety')
def int_to_text(number):
"""Converts an integer to the English language name of that integer.
E.g. converts 1 to "One". Supports numbers 0 to 999999.
This can be used in LilyPond identifiers (that do not support digits).
Included from python-ly project
:param number : an integer (e.g 42)
:return string that describes the number (e.g. FortyTwo)
"""
result = []
if number >= 1000:
hundreds, number = divmod(number, 1000)
result.append(int_to_text(hundreds) + "Thousand")
if number >= 100:
tens, number = divmod(number, 100)
result.append(_nums[tens] + "Hundred")
if number < 20:
result.append(_nums[number])
else:
tens, number = divmod(number, 10)
result.append(_tens[tens-2] + _nums[number])
text = "".join(result)
return text or 'Zero'
def int_to_letter(number, chars=string.ascii_uppercase):
"""Converts an integer to one or more letters.
E.g. 1 -> A, 2 -> B, ... 26 -> Z, 27 -> AA, etc.
Zero returns the empty string.
chars is the string to pick characters from, defaulting to
string.ascii_uppercase.
:param number: an integer
:param chars: alfabeth from which to choose characters to encode number
:return: the integer encoded in a series of characters
"""
mod = len(chars)
result = []
while number > 0:
number, c = divmod(number - 1, mod)
result.append(c)
return "".join(chars[c] for c in reversed(result))
def starts_with_one_of(strng, list_of_strings):
"""
:param strng:
:param list_of_strings:
:return: true if strng starts with one of the entries in list_of_strings
"""
for s in list_of_strings:
if strng.startswith(s):
return True
return False
def is_valid_music_numeral(s):
"""
checks if given roman number makes sense as a scale degree
:param s: roman numeral (string)
:return: true if valid scale degree, false otherwise
"""
return s in ["I", "II", "III", "IV", "V", "VI", "VII", "VIII"]
def split_roman_prefix(s):
"""
splits a roman numeral like VIbm7 into roman number, accidental, modifier
:param s:(e.g. VIbm7)
:return: (VI,b,m7)
"""
s = s.strip()
for i in reversed(range(len(s)+1)):
if i > 0:
prefix = s[:i]
if is_valid_music_numeral(prefix):
suffix = s[i:]
accidental = ""
if starts_with_one_of(suffix, ["bb", "##"]):
accidental = suffix[:2]
suffix = suffix[2:]
elif starts_with_one_of(suffix, ["b", "#"]):
accidental = suffix[:1]
suffix = suffix[1:]
return prefix, accidental, suffix
return None, None, None
if __name__ == "__main__":
print(int_to_roman(7))
print(int_to_roman(1832))
print(roman_to_int("IX"))
print(roman_to_int("VII"))
print(roman_to_int("XM"))
print(int_to_text(12323))
print(int_to_letter(28))
print(split_roman_prefix("IVm"))
print(split_roman_prefix("IV"))