format_de.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 from math import floor
20 
21 months = ['januar', 'februar', 'märz', 'april', 'mai', 'juni',
22  'juli', 'august', 'september', 'oktober', 'november',
23  'dezember']
24 
25 NUM_STRING_DE = {
26  0: 'null',
27  1: 'ein', # ein Viertel etc., nicht eins Viertel
28  2: 'zwei',
29  3: 'drei',
30  4: 'vier',
31  5: u'fünf',
32  6: 'sechs',
33  7: 'sieben',
34  8: 'acht',
35  9: 'neun',
36  10: 'zehn',
37  11: 'elf',
38  12: u'zwölf',
39  13: 'dreizehn',
40  14: 'vierzehn',
41  15: u'fünfzehn',
42  16: 'sechzehn',
43  17: 'siebzehn',
44  18: 'achtzehn',
45  19: 'neunzehn',
46  20: 'zwanzig',
47  30: u'dreißig',
48  40: 'vierzig',
49  50: u'fünfzig',
50  60: 'sechzig',
51  70: 'siebzig',
52  80: 'achtzig',
53  90: 'neunzig',
54  100: 'hundert'
55 }
56 
57 # German uses "long scale" https://en.wikipedia.org/wiki/Long_and_short_scales
58 # Currently, numbers are limited to 1000000000000000000000000,
59 # but NUM_POWERS_OF_TEN can be extended to include additional number words
60 
61 
62 NUM_POWERS_OF_TEN = [
63  '', 'tausend', 'Million', 'Milliarde', 'Billion', 'Billiarde', 'Trillion',
64  'Trilliarde'
65 ]
66 
67 FRACTION_STRING_DE = {
68  2: 'halb',
69  3: 'drittel',
70  4: 'viertel',
71  5: u'fünftel',
72  6: 'sechstel',
73  7: 'siebtel',
74  8: 'achtel',
75  9: 'neuntel',
76  10: 'zehntel',
77  11: 'elftel',
78  12: u'zwölftel',
79  13: 'dreizehntel',
80  14: 'vierzehntel',
81  15: u'fünfzehntel',
82  16: 'sechzehntel',
83  17: 'siebzehntel',
84  18: 'achtzehntel',
85  19: 'neunzehntel',
86  20: 'zwanzigstel'
87 }
88 
89 # Numbers below 1 million are written in one word in German, yielding very
90 # long words
91 # In some circumstances it may better to seperate individual words
92 # Set EXTRA_SPACE=" " for separating numbers below 1 million (
93 # orthographically incorrect)
94 # Set EXTRA_SPACE="" for correct spelling, this is standard
95 
96 # EXTRA_SPACE = " "
97 EXTRA_SPACE = ""
98 
99 
100 def nice_number_de(number, speech, denominators):
101  """ German helper for nice_number
102  This function formats a float to human understandable functions. Like
103  4.5 becomes "4 einhalb" for speech and "4 1/2" for text
104  Args:
105  number (int or float): the float to format
106  speech (bool): format for speech (True) or display (False)
107  denominators (iter of ints): denominators to use, default [1 .. 20]
108  Returns:
109  (str): The formatted string.
110  """
111  result = convert_to_mixed_fraction(number, denominators)
112  if not result:
113  # Give up, just represent as a 3 decimal number
114  return str(round(number, 3)).replace(".", ",")
115  whole, num, den = result
116  if not speech:
117  if num == 0:
118  # TODO: Number grouping? E.g. "1,000,000"
119  return str(whole)
120  else:
121  return '{} {}/{}'.format(whole, num, den)
122  if num == 0:
123  return str(whole)
124  den_str = FRACTION_STRING_DE[den]
125  if whole == 0:
126  if num == 1:
127  return_string = 'ein {}'.format(den_str)
128  else:
129  return_string = '{} {}'.format(num, den_str)
130  elif num == 1:
131  return_string = '{} und ein {}'.format(whole, den_str)
132  else:
133  return_string = '{} und {} {}'.format(whole, num, den_str)
134 
135  return return_string
136 
137 
138 def pronounce_number_de(num, places=2):
139  """
140  Convert a number to its spoken equivalent
141  For example, '5.2' would return 'five point two'
142  Args:
143  num(float or int): the number to pronounce (set limit below)
144  places(int): maximum decimal places to speak
145  Returns:
146  (str): The pronounced number
147 
148  """
149 
150  def pronounce_triplet_de(num):
151  result = ""
152  num = floor(num)
153  if num > 99:
154  hundreds = floor(num / 100)
155  if hundreds > 0:
156  result += NUM_STRING_DE[
157  hundreds] + EXTRA_SPACE + 'hundert' + EXTRA_SPACE
158  num -= hundreds * 100
159  if num == 0:
160  result += '' # do nothing
161  elif num == 1:
162  result += 'eins' # need the s for the last digit
163  elif num <= 20:
164  result += NUM_STRING_DE[num] # + EXTRA_SPACE
165  elif num > 20:
166  ones = num % 10
167  tens = num - ones
168  if ones > 0:
169  result += NUM_STRING_DE[ones] + EXTRA_SPACE
170  if tens > 0:
171  result += 'und' + EXTRA_SPACE
172  if tens > 0:
173  result += NUM_STRING_DE[tens] + EXTRA_SPACE
174  return result
175 
176  def pronounce_fractional_de(num,
177  places): # fixed number of places even with
178  # trailing zeros
179  result = ""
180  place = 10
181  while places > 0: # doesn't work with 1.0001 and places = 2: int(
182  # num*place) % 10 > 0 and places > 0:
183  result += " " + NUM_STRING_DE[int(num * place) % 10]
184  if int(num * place) % 10 == 1:
185  result += 's' # "1" is pronounced "eins" after the decimal
186  # point
187  place *= 10
188  places -= 1
189  return result
190 
191  def pronounce_whole_number_de(num, scale_level=0):
192  if num == 0:
193  return ''
194 
195  num = floor(num)
196  result = ''
197  last_triplet = num % 1000
198 
199  if last_triplet == 1:
200  if scale_level == 0:
201  if result != '':
202  result += '' + 'eins'
203  else:
204  result += "eins"
205  elif scale_level == 1:
206  result += 'ein' + EXTRA_SPACE + 'tausend' + EXTRA_SPACE
207  else:
208  result += "eine " + NUM_POWERS_OF_TEN[scale_level] + ' '
209  elif last_triplet > 1:
210  result += pronounce_triplet_de(last_triplet)
211  if scale_level == 1:
212  # result += EXTRA_SPACE
213  result += 'tausend' + EXTRA_SPACE
214  if scale_level >= 2:
215  # if EXTRA_SPACE == '':
216  # result += " "
217  result += " " + NUM_POWERS_OF_TEN[scale_level]
218  if scale_level >= 2:
219  if scale_level % 2 == 0:
220  result += "e" # MillionE
221  result += "n " # MilliardeN, MillioneN
222 
223  num = floor(num / 1000)
224  scale_level += 1
225  return pronounce_whole_number_de(num,
226  scale_level) + result # + EXTRA_SPACE
227 
228  result = ""
229  if abs(num) >= 1000000000000000000000000: # cannot do more than this
230  return str(num)
231  elif num == 0:
232  return str(NUM_STRING_DE[0])
233  elif num < 0:
234  return "minus " + pronounce_number_de(abs(num), places)
235  else:
236  if num == int(num):
237  return pronounce_whole_number_de(num)
238  else:
239  whole_number_part = floor(num)
240  fractional_part = num - whole_number_part
241  result += pronounce_whole_number_de(whole_number_part)
242  if places > 0:
243  result += " Komma"
244  result += pronounce_fractional_de(fractional_part, places)
245  return result
246 
247 
249  # ordinals for 1, 3, 7 and 8 are irregular
250  # this produces the base form, it will have to be adapted for genus,
251  # casus, numerus
252 
253  ordinals = ["nullte", "erste", "zweite", "dritte", "vierte", u"fünfte",
254  "sechste", "siebte", "achte"]
255 
256  # only for whole positive numbers including zero
257  if num < 0 or num != int(num):
258  return num
259  elif num < 9:
260  return ordinals[num]
261  elif num < 20:
262  return pronounce_number_de(num) + "te"
263  else:
264  return pronounce_number_de(num) + "ste"
265 
266 
267 def nice_time_de(dt, speech=True, use_24hour=False, use_ampm=False):
268  """
269  Format a time to a comfortable human format
270 
271  For example, generate 'five thirty' for speech or '5:30' for
272  text display.
273 
274  Args:
275  dt (datetime): date to format (assumes already in local timezone)
276  speech (bool): format for speech (default/True) or display (False)=Fal
277  use_24hour (bool): output in 24-hour/military or 12-hour format
278  use_ampm (bool): include the am/pm for 12-hour format
279  Returns:
280  (str): The formatted time string
281  """
282  if use_24hour:
283  # e.g. "03:01" or "14:22"
284  string = dt.strftime("%H:%M")
285  else:
286  if use_ampm:
287  # e.g. "3:01 AM" or "2:22 PM"
288  string = dt.strftime("%I:%M %p")
289  else:
290  # e.g. "3:01" or "2:22"
291  string = dt.strftime("%I:%M")
292  if string[0] == '0':
293  string = string[1:] # strip leading zeros
294 
295  if not speech:
296  return string
297 
298  # Generate a speakable version of the time
299  speak = ""
300  if use_24hour:
301  if dt.hour == 1:
302  speak += "ein" # 01:00 is "ein Uhr" not "eins Uhr"
303  else:
304  speak += pronounce_number_de(dt.hour)
305  speak += " Uhr"
306  if not dt.minute == 0: # zero minutes are not pronounced, 13:00 is
307  # "13 Uhr" not "13 hundred hours"
308  speak += " " + pronounce_number_de(dt.minute)
309 
310  return speak # ampm is ignored when use_24hour is true
311  else:
312  if dt.hour == 0 and dt.minute == 0:
313  return "Mitternacht"
314  if dt.hour == 12 and dt.minute == 0:
315  return "Mittag"
316  # TODO: "half past 3", "a quarter of 4" and other idiomatic times
317 
318  if dt.hour == 0:
319  speak += pronounce_number_de(12)
320  elif dt.hour <= 13:
321  if dt.hour == 1 or dt.hour == 13: # 01:00 and 13:00 is "ein Uhr"
322  # not "eins Uhr"
323  speak += 'ein'
324  else:
325  speak += pronounce_number_de(dt.hour)
326  else:
327  speak += pronounce_number_de(dt.hour - 12)
328 
329  speak += " Uhr"
330 
331  if not dt.minute == 0:
332  speak += " " + pronounce_number_de(dt.minute)
333 
334  if use_ampm:
335  if dt.hour > 11:
336  if dt.hour < 18:
337  speak += " nachmittags" # 12:01 - 17:59
338  # nachmittags/afternoon
339  elif dt.hour < 22:
340  speak += " abends" # 18:00 - 21:59 abends/evening
341  else:
342  speak += " nachts" # 22:00 - 23:59 nachts/at night
343  elif dt.hour < 3:
344  speak += " nachts" # 00:01 - 02:59 nachts/at night
345  else:
346  speak += " morgens" # 03:00 - 11:59 morgens/in the morning
347 
348  return speak
349 
350 
352  # check for months and call nice_ordinal_de declension of ordinals
353  # replace "^" with "hoch" (to the power of)
354  words = text.split()
355 
356  for idx, word in enumerate(words):
357  if word.lower() in months:
358  text = nice_ordinal_de(text)
359 
360  if word == '^':
361  wordNext = words[idx + 1] if idx + 1 < len(words) else ""
362  if wordNext.isnumeric():
363  words[idx] = "hoch"
364  text = " ".join(words)
365  return text
366 
367 
368 def nice_ordinal_de(text):
369  # check for months for declension of ordinals before months
370  # depending on articles/prepositions
371  normalized_text = text
372  words = text.split()
373 
374  for idx, word in enumerate(words):
375  wordNext = words[idx + 1] if idx + 1 < len(words) else ""
376  wordPrev = words[idx - 1] if idx > 0 else ""
377  if word[-1:] == ".":
378  if word[:-1].isdecimal():
379  if wordNext.lower() in months:
380  word = pronounce_ordinal_de(int(word[:-1]))
381  if wordPrev.lower() in ["am", "dem", "vom", "zum",
382  "(vom", "(am", "zum"]:
383  word += "n"
384  elif wordPrev.lower() not in ["der", "die", "das"]:
385  word += "r"
386  words[idx] = word
387  normalized_text = " ".join(words)
388  return normalized_text
def nice_time_de(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_de.py:267
def pronounce_number_de(num, places=2)
Definition: format_de.py:138
def nice_number_de(number, speech, denominators)
Definition: format_de.py:100
def convert_to_mixed_fraction(number, denominators)


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