88def _parse_text_and_convert(from_query, to_query) -> str | None:
89
90
91
92 if not (from_query and to_query):
93 return None
94
95 measured = re.match(RE_MEASURE, from_query, re.VERBOSE)
96 if not (measured and measured.group('number'), measured.group('unit')):
97 return None
98
99
100
101
102
103
104
105 source_list, target_list = [], []
106
107 for symbol, si_name, from_si, to_si, orig_symbol in symbol_to_si():
108
109 if symbol == measured.group('unit'):
110 source_list.append((si_name, to_si))
111 if symbol == to_query:
112 target_list.append((si_name, from_si, orig_symbol))
113
114 if not (source_list and target_list):
115 return None
116
117 source_to_si = target_from_si = target_symbol = None
118
119
120
121 for source in source_list:
122 for target in target_list:
123 if source[0] == target[0]:
124 source_to_si = source[1]
125 target_from_si = target[1]
126 target_symbol = target[2]
127
128 if not (source_to_si and target_from_si):
129 return None
130
131 _locale = get_locale() or 'en_US'
132
133 value = measured.group('sign') + measured.group('number') + (measured.group('E') or '')
134 value = babel.numbers.parse_decimal(value, locale=_locale)
135
136
137
138 if isinstance(source_to_si, (float, int)):
139 value = float(value) * source_to_si
140 else:
141 value = source_to_si(float(value))
142
143
144
145 if isinstance(target_from_si, (float, int)):
146 value = float(value) * target_from_si
147 else:
148 value = target_from_si(float(value))
149
150 if measured.group('E'):
151
152 result = babel.numbers.format_scientific(value, locale=_locale)
153 else:
154 result = babel.numbers.format_decimal(value, locale=_locale, format='#,##0.##########;-#')
155
156 return f'{result} {target_symbol}'