%PDF- %PDF-
| Direktori : /usr/lib/calibre/calibre/library/catalogs/ |
| Current File : //usr/lib/calibre/calibre/library/catalogs/utils.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2010, Greg Riker'
__docformat__ = 'restructuredtext en'
import re
from calibre import prints
from calibre.utils.logging import default_log as log
class NumberToText: # {{{
'''
Converts numbers to text
4.56 => four point fifty-six
456 => four hundred fifty-six
4:56 => four fifty-six
'''
ORDINALS = ['zeroth','first','second','third','fourth','fifth','sixth','seventh','eighth','ninth']
lessThanTwenty = ["<zero>","one","two","three","four","five","six","seven","eight","nine",
"ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen",
"eighteen","nineteen"]
tens = ["<zero>","<tens>","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"]
hundreds = ["<zero>","one","two","three","four","five","six","seven","eight","nine"]
def __init__(self, number, verbose=False):
self.number = number
self.number_as_float = 0.0
self.text = ''
self.verbose = verbose
self.log = log
self.numberTranslate()
def stringFromInt(self, intToTranslate):
# Convert intToTranslate to string
# intToTranslate is a three-digit number
tensComponentString = ""
hundredsComponent = intToTranslate - (intToTranslate % 100)
tensComponent = intToTranslate % 100
# Build the hundreds component
if hundredsComponent:
hundredsComponentString = "%s hundred" % self.hundreds[hundredsComponent//100]
else:
hundredsComponentString = ""
# Build the tens component
if tensComponent < 20:
tensComponentString = self.lessThanTwenty[tensComponent]
else:
tensPart = ""
onesPart = ""
# Get the tens part
tensPart = self.tens[tensComponent // 10]
onesPart = self.lessThanTwenty[tensComponent % 10]
if intToTranslate % 10:
tensComponentString = f"{tensPart}-{onesPart}"
else:
tensComponentString = "%s" % tensPart
# Concatenate the results
result = ''
if hundredsComponent and not tensComponent:
result = hundredsComponentString
elif not hundredsComponent and tensComponent:
result = tensComponentString
elif hundredsComponent and tensComponent:
result = hundredsComponentString + " " + tensComponentString
else:
prints(" NumberToText.stringFromInt(): empty result translating %d" % intToTranslate)
return result
def numberTranslate(self):
hundredsNumber = 0
thousandsNumber = 0
hundredsString = ""
thousandsString = ""
resultString = ""
self.suffix = ''
if self.verbose:
self.log("numberTranslate(): %s" % self.number)
# Special case ordinals
if re.search('[st|nd|rd|th]',self.number):
self.number = re.sub(',','',self.number)
ordinal_suffix = re.search(r'[\D]', self.number)
ordinal_number = re.sub(r'\D','',re.sub(',','',self.number))
if self.verbose:
self.log("Ordinal: %s" % ordinal_number)
self.number_as_float = ordinal_number
self.suffix = self.number[ordinal_suffix.start():]
if int(ordinal_number) > 9:
# Some typos (e.g., 'twentyth'), acceptable
self.text = '%s' % (NumberToText(ordinal_number).text)
else:
self.text = '%s' % (self.ORDINALS[int(ordinal_number)])
# Test for time
elif re.search(':',self.number):
if self.verbose:
self.log("Time: %s" % self.number)
self.number_as_float = re.sub(':','.',self.number)
time_strings = self.number.split(":")
hours = NumberToText(time_strings[0]).text
minutes = NumberToText(time_strings[1]).text
self.text = f'{hours.capitalize()}-{minutes}'
# Test for %
elif re.search('%', self.number):
if self.verbose:
self.log("Percent: %s" % self.number)
self.number_as_float = self.number.split('%')[0]
self.text = NumberToText(self.number.replace('%',' percent')).text
# Test for decimal
elif re.search('\\.',self.number):
if self.verbose:
self.log("Decimal: %s" % self.number)
self.number_as_float = self.number
decimal_strings = self.number.split(".")
left = NumberToText(decimal_strings[0]).text
right = NumberToText(decimal_strings[1]).text
self.text = f'{left.capitalize()} point {right}'
# Test for hyphenated
elif re.search('-', self.number):
if self.verbose:
self.log("Hyphenated: %s" % self.number)
self.number_as_float = self.number.split('-')[0]
strings = self.number.split('-')
if re.search('[0-9]+', strings[0]):
left = NumberToText(strings[0]).text
right = strings[1]
else:
left = strings[0]
right = NumberToText(strings[1]).text
self.text = f'{left}-{right}'
# Test for only commas and numbers
elif re.search(',', self.number) and not re.search('[^0-9,]',self.number):
if self.verbose:
self.log("Comma(s): %s" % self.number)
self.number_as_float = re.sub(',','',self.number)
self.text = NumberToText(self.number_as_float).text
# Test for hybrid e.g., 'K2, 2nd, 10@10'
elif re.search('[\\D]+', self.number):
if self.verbose:
self.log("Hybrid: %s" % self.number)
# Split the token into number/text
number_position = re.search(r'\d',self.number).start()
text_position = re.search(r'\D',self.number).start()
if number_position < text_position:
number = self.number[:text_position]
text = self.number[text_position:]
self.text = f'{NumberToText(number).text}{text}'
else:
text = self.number[:number_position]
number = self.number[number_position:]
self.text = f'{text}{NumberToText(number).text}'
else:
if self.verbose:
self.log("Clean: %s" % self.number)
try:
self.float_as_number = float(self.number)
number = int(self.number)
except:
return
if number > 10**9:
self.text = "%d out of range" % number
return
if number == 10**9:
self.text = "one billion"
else :
# Isolate the three-digit number groups
millionsNumber = number//10**6
thousandsNumber = (number - (millionsNumber * 10**6))//10**3
hundredsNumber = number - (millionsNumber * 10**6) - (thousandsNumber * 10**3)
if self.verbose:
print(f"Converting {millionsNumber} {thousandsNumber} {hundredsNumber}")
# Convert hundredsNumber
if hundredsNumber :
hundredsString = self.stringFromInt(hundredsNumber)
# Convert thousandsNumber
if thousandsNumber:
if number > 1099 and number < 2000:
resultString = '{} {}'.format(self.lessThanTwenty[number//100],
self.stringFromInt(number % 100))
self.text = resultString.strip().capitalize()
return
else:
thousandsString = self.stringFromInt(thousandsNumber)
# Convert millionsNumber
if millionsNumber:
millionsString = self.stringFromInt(millionsNumber)
# Concatenate the strings
resultString = ''
if millionsNumber:
resultString += "%s million " % millionsString
if thousandsNumber:
resultString += "%s thousand " % thousandsString
if hundredsNumber:
resultString += "%s" % hundredsString
if not millionsNumber and not thousandsNumber and not hundredsNumber:
resultString = "zero"
if self.verbose:
self.log('resultString: %s' % resultString)
self.text = resultString.strip().capitalize()
# }}}