215def _parse_text_and_convert(from_query, to_query) -> str | None:
216
217
218
219 if not (from_query and to_query):
220 return None
221
222 measured = re.match(RE_MEASURE, from_query, re.VERBOSE)
223 if not (measured and measured.group('number'), measured.group('unit')):
224 return None
225
226
227
228
229
230
231
232 source_list, target_list = [], []
233
234 for symbol, si_name, from_si, to_si, orig_symbol in symbol_to_si():
235
236 if symbol == measured.group('unit'):
237 source_list.append((si_name, to_si))
238 if symbol == to_query:
239 target_list.append((si_name, from_si, orig_symbol))
240
241 if not (source_list and target_list):
242 return None
243
244 source_to_si = target_from_si = target_symbol = None
245
246
247
248 for source in source_list:
249 for target in target_list:
250 if source[0] == target[0]:
251 source_to_si = source[1]
252 target_from_si = target[1]
253 target_symbol = target[2]
254
255 if not (source_to_si and target_from_si):
256 return None
257
258 _locale = get_locale() or 'en_US'
259
260 value = measured.group('sign') + measured.group('number') + (measured.group('E') or '')
261 value = babel.numbers.parse_decimal(value, locale=_locale)
262
263
264
265 if isinstance(source_to_si, (float, int)):
266 value = float(value) * source_to_si
267 else:
268 value = source_to_si(float(value))
269
270
271
272 if isinstance(target_from_si, (float, int)):
273 value = float(value) * target_from_si
274 else:
275 value = target_from_si(float(value))
276
277 if measured.group('E'):
278
279 result = babel.numbers.format_scientific(value, locale=_locale)
280 else:
281 result = babel.numbers.format_decimal(value, locale=_locale, format='#,##0.##########;-#')
282
283 return f'{result} {target_symbol}'