format_it.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright 2017 Mycroft AI Inc.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17 
18 from mycroft.util.lang.format_common import convert_to_mixed_fraction
19 import collections
20 
21 NUM_STRING_IT = {
22  0: 'zero',
23  1: 'uno',
24  2: 'due',
25  3: 'tre',
26  4: 'quattro',
27  5: 'cinque',
28  6: 'sei',
29  7: 'sette',
30  8: 'otto',
31  9: 'nove',
32  10: 'dieci',
33  11: 'undici',
34  12: 'dodici',
35  13: 'tredici',
36  14: 'quattordici',
37  15: 'quindici',
38  16: 'sedici',
39  17: 'diciassette',
40  18: 'diciotto',
41  19: 'diciannove',
42  20: 'venti',
43  30: 'trenta',
44  40: 'quaranta',
45  50: 'cinquanta',
46  60: 'sessanta',
47  70: 'settanta',
48  80: 'ottanta',
49  90: 'novanta'
50 }
51 
52 FRACTION_STRING_IT = {
53  2: 'mezz',
54  3: 'terz',
55  4: 'quart',
56  5: 'quint',
57  6: 'sest',
58  7: 'settim',
59  8: 'ottav',
60  9: 'non',
61  10: 'decim',
62  11: 'undicesim',
63  12: 'dodicesim',
64  13: 'tredicesim',
65  14: 'quattordicesim',
66  15: 'quindicesim',
67  16: 'sedicesim',
68  17: 'diciassettesim',
69  18: 'diciottesim',
70  19: 'diciannovesim',
71  20: 'ventesim'
72 }
73 
74 # fonte: http://tulengua.es/numeros-texto/default.aspx
75 LONG_SCALE_IT = collections.OrderedDict([
76  (100, 'cento'),
77  (1000, 'mila'),
78  (1000000, 'milioni'),
79  (1e9, "miliardi"),
80  (1e12, "bilioni"),
81  (1e18, 'trilioni'),
82  (1e24, "quadrilioni"),
83  (1e30, "quintilioni"),
84  (1e36, "sestilioni"),
85  (1e42, "settilioni"),
86  (1e48, "ottillioni"),
87  (1e54, "nonillioni"),
88  (1e60, "decemillioni"),
89  (1e66, "undicilione"),
90  (1e72, "dodicilione"),
91  (1e78, "tredicilione"),
92  (1e84, "quattordicilione"),
93  (1e90, "quindicilione"),
94  (1e96, "sedicilione"),
95  (1e102, "diciasettilione"),
96  (1e108, "diciottilione"),
97  (1e114, "dicianovilione"),
98  (1e120, "vintilione"),
99  (1e306, "unquinquagintilione"),
100  (1e312, "duoquinquagintilione"),
101  (1e336, "sesquinquagintilione"),
102  (1e366, "unsexagintilione")
103 ])
104 
105 
106 SHORT_SCALE_IT = collections.OrderedDict([
107  (100, 'cento'),
108  (1000, 'mila'),
109  (1000000, 'milioni'),
110  (1e9, "miliardi"),
111  (1e12, 'bilioni'),
112  (1e15, "biliardi"),
113  (1e18, "trilioni"),
114  (1e21, "triliardi"),
115  (1e24, "quadrilioni"),
116  (1e27, "quadriliardi"),
117  (1e30, "quintilioni"),
118  (1e33, "quintiliardi"),
119  (1e36, "sestilioni"),
120  (1e39, "sestiliardi"),
121  (1e42, "settilioni"),
122  (1e45, "settiliardi"),
123  (1e48, "ottilioni"),
124  (1e51, "ottiliardi"),
125  (1e54, "nonilioni"),
126  (1e57, "noniliardi"),
127  (1e60, "decilioni"),
128  (1e63, "deciliardi"),
129  (1e66, "undicilioni"),
130  (1e69, "undiciliardi"),
131  (1e72, "dodicilioni"),
132  (1e75, "dodiciliardi"),
133  (1e78, "tredicilioni"),
134  (1e81, "trediciliardi"),
135  (1e84, "quattordicilioni"),
136  (1e87, "quattordiciliardi"),
137  (1e90, "quindicilioni"),
138  (1e93, "quindiciliardi"),
139  (1e96, "sedicilioni"),
140  (1e99, "sediciliardi"),
141  (1e102, "diciassettilioni"),
142  (1e105, "diciassettiliardi"),
143  (1e108, "diciottilioni"),
144  (1e111, "diciottiliardi"),
145  (1e114, "dicianovilioni"),
146  (1e117, "dicianoviliardi"),
147  (1e120, "vintilioni"),
148  (1e123, "vintiliardi"),
149  (1e153, "quinquagintillion"),
150  (1e183, "sexagintillion"),
151  (1e213, "septuagintillion"),
152  (1e243, "ottogintilioni"),
153  (1e273, "nonigintillioni"),
154  (1e303, "centilioni"),
155  (1e306, "uncentilioni"),
156  (1e309, "duocentilioni"),
157  (1e312, "trecentilioni"),
158  (1e333, "decicentilioni"),
159  (1e336, "undicicentilioni"),
160  (1e363, "viginticentilioni"),
161  (1e366, "unviginticentilioni"),
162  (1e393, "trigintacentilioni"),
163  (1e423, "quadragintacentillion"),
164  (1e453, "quinquagintacentillion"),
165  (1e483, "sexagintacentillion"),
166  (1e513, "septuagintacentillion"),
167  (1e543, "ctogintacentillion"),
168  (1e573, "nonagintacentillion"),
169  (1e603, "ducentillion"),
170  (1e903, "trecentillion"),
171  (1e1203, "quadringentillion"),
172  (1e1503, "quingentillion"),
173  (1e1803, "sescentillion"),
174  (1e2103, "septingentillion"),
175  (1e2403, "octingentillion"),
176  (1e2703, "nongentillion"),
177  (1e3003, "millinillion")
178 ])
179 
180 
181 def nice_number_it(number, speech, denominators):
182  """ Italian helper for nice_number
183 
184  This function formats a float to human understandable functions. Like
185  4.5 becomes "4 e un mezz" for speech and "4 1/2" for text
186 
187  Args:
188  number (int or float): the float to format
189  speech (bool): format for speech (True) or display (False)
190  denominators (iter of ints): denominators to use, default [1 .. 20]
191  Returns:
192  (str): The formatted string.
193  """
194 
195  result = convert_to_mixed_fraction(number, denominators)
196  if not result:
197  # Give up, just represent as a 3 decimal number
198  return str(round(number, 3))
199 
200  whole, num, den = result
201 
202  if not speech:
203  if num == 0:
204  return str(whole)
205  else:
206  return '{} {}/{}'.format(whole, num, den)
207 
208  if num == 0:
209  return str(whole)
210  # denominatore
211  den_str = FRACTION_STRING_IT[den]
212  # frazione
213  if whole == 0:
214  if num == 1:
215  # un decimo
216  return_string = 'un {}'.format(den_str)
217  else:
218  # tre mezzi
219  return_string = '{} {}'.format(num, den_str)
220  # interi >10
221  elif num == 1:
222  # trenta e un
223  return_string = '{} e un {}'.format(whole, den_str)
224  # interi >10 con frazioni
225  else:
226  # venti e 3 decimi
227  return_string = '{} e {} {}'.format(whole, num, den_str)
228 
229  # gestisce il plurale del denominatore
230  if num > 1:
231  return_string += 'i'
232  else:
233  return_string += 'o'
234 
235  return return_string
236 
237 
238 def pronounce_number_it(num, places=2, short_scale=False, scientific=False):
239  """
240  Convert a number to it's spoken equivalent
241  adapted to italian fron en version
242 
243  For example, '5.2' would return 'cinque virgola due'
244 
245  Args:
246  num(float or int): the number to pronounce (under 100)
247  places(int): maximum decimal places to speak
248  short_scale (bool) : use short (True) or long scale (False)
249  https://en.wikipedia.org/wiki/Names_of_large_numbers
250  scientific (bool): pronounce in scientific notation
251  Returns:
252  (str): The pronounced number
253  """
254  # gestione infinito
255  if num == float("inf"):
256  return "infinito"
257  elif num == float("-inf"):
258  return "meno infinito"
259 
260  if scientific:
261  number = '%E' % num
262  n, power = number.replace("+", "").split("E")
263  power = int(power)
264  if power != 0:
265  return '{}{} per dieci elevato alla {}{}'.format(
266  'meno ' if float(n) < 0 else '',
267  pronounce_number_it(abs(float(n)), places, short_scale, False),
268  'meno ' if power < 0 else '',
269  pronounce_number_it(abs(power), places, short_scale, False))
270 
271  if short_scale:
272  number_names = NUM_STRING_IT.copy()
273  number_names.update(SHORT_SCALE_IT)
274  else:
275  number_names = NUM_STRING_IT.copy()
276  number_names.update(LONG_SCALE_IT)
277 
278  digits = [number_names[n] for n in range(0, 20)]
279 
280  tens = [number_names[n] for n in range(10, 100, 10)]
281 
282  if short_scale:
283  hundreds = [SHORT_SCALE_IT[n] for n in SHORT_SCALE_IT.keys()]
284  else:
285  hundreds = [LONG_SCALE_IT[n] for n in LONG_SCALE_IT.keys()]
286 
287  # deal with negatives
288  result = ""
289  if num < 0:
290  result = "meno "
291  num = abs(num)
292 
293  # check for a direct match
294  if num in number_names:
295  if num > 90:
296  result += "" # inizio stringa
297  result += number_names[num]
298  else:
299  def _sub_thousand(n):
300  assert 0 <= n <= 999
301  if n <= 19:
302  return digits[n]
303  elif n <= 99:
304  q, r = divmod(n, 10)
305  _deci = tens[q-1]
306  _unit = r
307  _partial = _deci
308  if _unit > 0:
309  if _unit == 1 or _unit == 8:
310  _partial = _partial[:-1] # ventuno ventotto
311  _partial += number_names[_unit]
312  return _partial
313  else:
314  q, r = divmod(n, 100)
315  if q == 1:
316  _partial = "cento"
317  else:
318  _partial = digits[q] + "cento"
319  _partial += (
320  " " + _sub_thousand(r) if r else "") # separa centinaia
321  return _partial
322 
323  def _short_scale(n):
324  if n >= max(SHORT_SCALE_IT.keys()):
325  return "numero davvero enorme"
326  n = int(n)
327  assert 0 <= n
328  res = []
329  for i, z in enumerate(_split_by(n, 1000)):
330  if not z:
331  continue
332  number = _sub_thousand(z)
333  if i:
334  number += "" # separa ordini grandezza
335  number += hundreds[i]
336  res.append(number)
337 
338  return ", ".join(reversed(res))
339 
340  def _split_by(n, split=1000):
341  assert 0 <= n
342  res = []
343  while n:
344  n, r = divmod(n, split)
345  res.append(r)
346  return res
347 
348  def _long_scale(n):
349  if n >= max(LONG_SCALE_IT.keys()):
350  return "numero davvero enorme"
351  n = int(n)
352  assert 0 <= n
353  res = []
354  for i, z in enumerate(_split_by(n, 1000000)):
355  if not z:
356  continue
357  number = pronounce_number_it(z, places, True, scientific)
358  # strip off the comma after the thousand
359  if i:
360  # plus one as we skip 'thousand'
361  # (and 'hundred', but this is excluded by index value)
362  number = number.replace(',', '')
363  number += " " + hundreds[i+1]
364  res.append(number)
365  return ", ".join(reversed(res))
366 
367  if short_scale:
368  result += _short_scale(num)
369  else:
370  result += _long_scale(num)
371 
372  # normalizza unità misura singole e 'ragionevoli' ed ad inizio stringa
373  if result == 'mila':
374  result = 'mille'
375  if result == 'milioni':
376  result = 'un milione'
377  if result == 'miliardi':
378  result = 'un miliardo'
379  if result[0:7] == 'unomila':
380  result = result.replace('unomila', 'mille', 1)
381  if result[0:10] == 'unomilioni':
382  result = result.replace('unomilioni', 'un milione', 1)
383  # if result[0:11] == 'unomiliardi':
384  # result = result.replace('unomiliardi', 'un miliardo', 1)
385 
386  # Deal with fractional part
387  if not num == int(num) and places > 0:
388  result += " virgola"
389  place = 10
390  while int(num * place) % 10 > 0 and places > 0:
391  result += " " + number_names[int(num * place) % 10]
392  place *= 10
393  places -= 1
394  return result
395 
396 
397 def nice_time_it(dt, speech=True, use_24hour=False, use_ampm=False):
398  """
399  Format a time to a comfortable human format
400  adapted to italian fron en version
401 
402  For example, generate 'cinque e trenta' for speech or '5:30' for
403  text display.
404 
405  Args:
406  dt (datetime): date to format (assumes already in local timezone)
407  speech (bool): format for speech (default/True) or display (False)=Fal
408  use_24hour (bool): output in 24-hour/military or 12-hour format
409  use_ampm (bool): include the am/pm for 12-hour format
410  Returns:
411  (str): The formatted time string
412  """
413  if use_24hour:
414  # e.g. "03:01" or "14:22"
415  string = dt.strftime("%H:%M")
416  else:
417  if use_ampm:
418  # e.g. "3:01 AM" or "2:22 PM"
419  string = dt.strftime("%I:%M %p")
420  else:
421  # e.g. "3:01" or "2:22"
422  string = dt.strftime("%I:%M")
423  if string[0] == '0':
424  string = string[1:] # strip leading zeros
425 
426  if not speech:
427  return string
428 
429  # Generate a speakable version of the time
430  if use_24hour:
431  speak = ""
432  # Either "zero 8 zerozero" o "13 zerozero"
433  if string[0:2] == '00':
434  speak += "zerozero"
435  elif string[0] == '0':
436  speak += pronounce_number_it(int(string[0])) + " "
437  if int(string[1]) == 1:
438  speak = "una"
439  else:
440  speak += pronounce_number_it(int(string[1]))
441  else:
442  speak = pronounce_number_it(int(string[0:2]))
443 
444  # in italian "13 e 25"
445  speak += " e "
446 
447  if string[3:5] == '00':
448  speak += "zerozero"
449  else:
450  if string[3] == '0':
451  speak += pronounce_number_it(0) + " "
452  speak += pronounce_number_it(int(string[4]))
453  else:
454  speak += pronounce_number_it(int(string[3:5]))
455  return speak
456  else:
457  if dt.hour == 0 and dt.minute == 0:
458  return "mezzanotte"
459  if dt.hour == 12 and dt.minute == 0:
460  return "mezzogiorno"
461  # TODO: "10 e un quarto", "4 e tre quarti" and ot her idiomatic times
462 
463  if dt.hour == 0:
464  speak = "mezzanotte"
465  elif dt.hour == 1 or dt.hour == 13:
466  speak = "una"
467  elif dt.hour > 13: # era minore
468  speak = pronounce_number_it(dt.hour-12)
469  else:
470  speak = pronounce_number_it(dt.hour)
471 
472  speak += " e"
473  if dt.minute == 0:
474  speak = speak[:-2]
475  if not use_ampm:
476  speak += " in punto"
477  elif dt.minute == 15:
478  speak += " un quarto"
479  elif dt.minute == 45:
480  speak += " tre quarti"
481  else:
482  if dt.minute < 10:
483  speak += " zero"
484  speak += " " + pronounce_number_it(dt.minute)
485 
486  if use_ampm:
487 
488  if dt.hour < 4:
489  speak.strip()
490  elif dt.hour > 20:
491  speak += " della notte"
492  elif dt.hour > 17:
493  speak += " della sera"
494  elif dt.hour > 12:
495  speak += " del pomeriggio"
496  else:
497  speak += " della mattina"
498 
499  return speak
def nice_time_it(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_it.py:397
def pronounce_number_it(num, places=2, short_scale=False, scientific=False)
Definition: format_it.py:238
def nice_number_it(number, speech, denominators)
Definition: format_it.py:181
def convert_to_mixed_fraction(number, denominators)


mycroft_ros
Author(s):
autogenerated on Mon Apr 26 2021 02:35:40