pyquantity 0.1.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyquantity/__init__.py +29 -0
- pyquantity/context.py +513 -0
- pyquantity/core.py +1185 -0
- pyquantity/parser.py +464 -0
- pyquantity-0.1.15.dist-info/METADATA +118 -0
- pyquantity-0.1.15.dist-info/RECORD +9 -0
- pyquantity-0.1.15.dist-info/WHEEL +5 -0
- pyquantity-0.1.15.dist-info/licenses/LICENSE +21 -0
- pyquantity-0.1.15.dist-info/top_level.txt +1 -0
pyquantity/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyquantity - A modern Python package for quantity calculations.
|
|
3
|
+
|
|
4
|
+
This package provides tools for working with physical quantities, units,
|
|
5
|
+
and dimensional analysis.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.15"
|
|
9
|
+
__author__ = "odysseu"
|
|
10
|
+
__email__ = "uboucherie1@gmail.com"
|
|
11
|
+
__license__ = "MIT"
|
|
12
|
+
|
|
13
|
+
from .context import (
|
|
14
|
+
MeasurementDatabase,
|
|
15
|
+
UnitParser,
|
|
16
|
+
extract_quantities,
|
|
17
|
+
find_units_in_text,
|
|
18
|
+
get_measurement,
|
|
19
|
+
parse_quantity,
|
|
20
|
+
)
|
|
21
|
+
from .core import Dimension, Quantity, UnitSystem
|
|
22
|
+
from .parser import QuantityParser, parse_quantities
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"Quantity", "Dimension", "UnitSystem",
|
|
26
|
+
"QuantityParser", "parse_quantities",
|
|
27
|
+
"MeasurementDatabase", "UnitParser",
|
|
28
|
+
"get_measurement", "parse_quantity", "extract_quantities", "find_units_in_text"
|
|
29
|
+
]
|
pyquantity/context.py
ADDED
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Contextual measurements and real-world object database for pyquantity.
|
|
3
|
+
|
|
4
|
+
This module provides a database of common real-world objects with their
|
|
5
|
+
associated measurements, as well as natural language parsing capabilities
|
|
6
|
+
for extracting units and measurements from text.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
from .core import Quantity, UnitSystem
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MeasurementDatabase:
|
|
15
|
+
"""
|
|
16
|
+
Database of real-world objects and their associated measurements.
|
|
17
|
+
|
|
18
|
+
This class provides a collection of common objects with standard
|
|
19
|
+
measurements (e.g., "normal bath" = 150 liters, "standard cup" = 250 ml).
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self) -> None:
|
|
23
|
+
# Initialize with standard measurements
|
|
24
|
+
self.measurements = {
|
|
25
|
+
# Volume measurements
|
|
26
|
+
"teaspoon": Quantity(5.0, "milliliter"),
|
|
27
|
+
"tablespoon": Quantity(15.0, "milliliter"),
|
|
28
|
+
"cup": Quantity(250.0, "milliliter"),
|
|
29
|
+
"glass": Quantity(200.0, "milliliter"),
|
|
30
|
+
"bottle": Quantity(500.0, "milliliter"),
|
|
31
|
+
"can": Quantity(330.0, "milliliter"),
|
|
32
|
+
"jug": Quantity(1.0, "liter"),
|
|
33
|
+
"bucket": Quantity(10.0, "liter"),
|
|
34
|
+
"bathtub": Quantity(150.0, "liter"),
|
|
35
|
+
"normal bath": Quantity(150.0, "liter"),
|
|
36
|
+
"swimming pool": Quantity(50000.0, "liter"),
|
|
37
|
+
"ocean": Quantity(1.332e21, "liter"), # Approximate volume of Earth's oceans
|
|
38
|
+
|
|
39
|
+
# Mass measurements
|
|
40
|
+
"grain of salt": Quantity(0.06, "milligram"),
|
|
41
|
+
"paperclip": Quantity(1.0, "gram"),
|
|
42
|
+
"apple": Quantity(150.0, "gram"),
|
|
43
|
+
"loaf of bread": Quantity(500.0, "gram"),
|
|
44
|
+
"bag of sugar": Quantity(1.0, "kilogram"),
|
|
45
|
+
"average person": Quantity(70.0, "kilogram"),
|
|
46
|
+
"car mass": Quantity(1500.0, "kilogram"),
|
|
47
|
+
"elephant": Quantity(5000.0, "kilogram"),
|
|
48
|
+
"blue whale": Quantity(150000.0, "kilogram"),
|
|
49
|
+
|
|
50
|
+
# Length measurements
|
|
51
|
+
"grain of sand": Quantity(0.5, "millimeter"),
|
|
52
|
+
"credit card": Quantity(85.6, "millimeter"),
|
|
53
|
+
"smartphone": Quantity(150.0, "millimeter"),
|
|
54
|
+
"pizza": Quantity(30.0, "centimeter"),
|
|
55
|
+
"door": Quantity(2.0, "meter"),
|
|
56
|
+
"room": Quantity(5.0, "meter"),
|
|
57
|
+
"football field length": Quantity(100.0, "meter"),
|
|
58
|
+
"marathon": Quantity(42.195, "kilometer"),
|
|
59
|
+
"mount everest": Quantity(8848.0, "meter"),
|
|
60
|
+
|
|
61
|
+
# Time measurements
|
|
62
|
+
"blink": Quantity(0.3, "second"),
|
|
63
|
+
"breath": Quantity(4.0, "second"),
|
|
64
|
+
"minute": Quantity(60.0, "second"),
|
|
65
|
+
"hour": Quantity(3600.0, "second"),
|
|
66
|
+
"day": Quantity(86400.0, "second"),
|
|
67
|
+
"week": Quantity(604800.0, "second"),
|
|
68
|
+
"month": Quantity(2.628e6, "second"), # Average month
|
|
69
|
+
"year": Quantity(3.154e7, "second"), # Average year
|
|
70
|
+
|
|
71
|
+
# Speed measurements
|
|
72
|
+
"snail": Quantity(0.05, "meter/second"),
|
|
73
|
+
"walking": Quantity(1.4, "meter/second"),
|
|
74
|
+
"running": Quantity(5.0, "meter/second"),
|
|
75
|
+
"cycling": Quantity(7.0, "meter/second"),
|
|
76
|
+
"car speed": Quantity(25.0, "meter/second"),
|
|
77
|
+
"high speed train": Quantity(83.0, "meter/second"),
|
|
78
|
+
"airplane": Quantity(250.0, "meter/second"),
|
|
79
|
+
"speed of sound": Quantity(343.0, "meter/second"),
|
|
80
|
+
"speed of light": Quantity(299792458.0, "meter/second"),
|
|
81
|
+
|
|
82
|
+
# Temperature measurements
|
|
83
|
+
"freezing point of water": Quantity(0.0, "celsius"),
|
|
84
|
+
"room temperature": Quantity(20.0, "celsius"),
|
|
85
|
+
"body temperature": Quantity(37.0, "celsius"),
|
|
86
|
+
"boiling point of water": Quantity(100.0, "celsius"),
|
|
87
|
+
"absolute zero": Quantity(-273.15, "celsius"),
|
|
88
|
+
"surface of the sun": Quantity(5500.0, "celsius"),
|
|
89
|
+
|
|
90
|
+
# Energy measurements
|
|
91
|
+
"calorie": Quantity(4.184, "joule"),
|
|
92
|
+
"food calorie": Quantity(4184.0, "joule"),
|
|
93
|
+
"battery": Quantity(10000.0, "joule"),
|
|
94
|
+
"car battery": Quantity(1.0e6, "joule"),
|
|
95
|
+
"gasoline liter": Quantity(3.42e7, "joule"),
|
|
96
|
+
"ton of tnt": Quantity(4.184e9, "joule"),
|
|
97
|
+
"atomic bomb": Quantity(8.4e13, "joule"), # Little Boy
|
|
98
|
+
|
|
99
|
+
# Power measurements
|
|
100
|
+
"light bulb": Quantity(60.0, "watt"),
|
|
101
|
+
"human": Quantity(100.0, "watt"),
|
|
102
|
+
"car engine": Quantity(100000.0, "watt"),
|
|
103
|
+
"jet engine": Quantity(1.0e8, "watt"),
|
|
104
|
+
"power plant": Quantity(1.0e9, "watt"),
|
|
105
|
+
"sun": Quantity(3.828e26, "watt"),
|
|
106
|
+
|
|
107
|
+
# Pressure measurements
|
|
108
|
+
"atmospheric pressure": Quantity(101325.0, "pascal"),
|
|
109
|
+
"car tire": Quantity(200000.0, "pascal"),
|
|
110
|
+
"bicycle tire": Quantity(400000.0, "pascal"),
|
|
111
|
+
"deep ocean": Quantity(1.0e7, "pascal"),
|
|
112
|
+
"marianas trench": Quantity(1.1e8, "pascal"),
|
|
113
|
+
|
|
114
|
+
# Area measurements
|
|
115
|
+
"postage stamp": Quantity(4.0, "square_centimeter"),
|
|
116
|
+
"a4 paper": Quantity(0.0625, "square_meter"),
|
|
117
|
+
"parking space": Quantity(12.0, "square_meter"),
|
|
118
|
+
"tennis court": Quantity(260.0, "square_meter"),
|
|
119
|
+
"football field area": Quantity(7140.0, "square_meter"),
|
|
120
|
+
"central park": Quantity(3.41e6, "square_meter"),
|
|
121
|
+
|
|
122
|
+
# Volume flow measurements
|
|
123
|
+
"faucet": Quantity(0.1, "liter/second"),
|
|
124
|
+
"shower": Quantity(0.2, "liter/second"),
|
|
125
|
+
"garden hose": Quantity(0.5, "liter/second"),
|
|
126
|
+
"fire hose": Quantity(10.0, "liter/second"),
|
|
127
|
+
"river": Quantity(1000.0, "cubic_meter/second"), # Amazon river
|
|
128
|
+
"niagara falls": Quantity(2400.0, "cubic_meter/second"),
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
def get_measurement(self, object_name: str) -> Quantity | None:
|
|
132
|
+
"""
|
|
133
|
+
Get the measurement for a given object name.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
object_name: The name of the object to look up
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
The Quantity object if found, None otherwise
|
|
140
|
+
|
|
141
|
+
Examples:
|
|
142
|
+
>>> db = MeasurementDatabase()
|
|
143
|
+
>>> bath = db.get_measurement("normal bath")
|
|
144
|
+
>>> print(bath)
|
|
145
|
+
150.0 liter
|
|
146
|
+
"""
|
|
147
|
+
object_name = object_name.lower().strip()
|
|
148
|
+
return self.measurements.get(object_name)
|
|
149
|
+
|
|
150
|
+
def add_measurement(self, object_name: str, quantity: Quantity) -> None:
|
|
151
|
+
"""
|
|
152
|
+
Add a new measurement to the database.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
object_name: The name of the object
|
|
156
|
+
quantity: The Quantity object representing the measurement
|
|
157
|
+
|
|
158
|
+
Examples:
|
|
159
|
+
>>> db = MeasurementDatabase()
|
|
160
|
+
>>> db.add_measurement("my cup", Quantity(300.0, "milliliter"))
|
|
161
|
+
"""
|
|
162
|
+
self.measurements[object_name.lower().strip()] = quantity
|
|
163
|
+
|
|
164
|
+
def find_measurements(self, search_term: str) -> list[tuple[str, Quantity]]:
|
|
165
|
+
"""
|
|
166
|
+
Find measurements matching a search term.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
search_term: The term to search for
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
List of (object_name, quantity) tuples that match the search
|
|
173
|
+
|
|
174
|
+
Examples:
|
|
175
|
+
>>> db = MeasurementDatabase()
|
|
176
|
+
>>> results = db.find_measurements("bath")
|
|
177
|
+
>>> for name, qty in results:
|
|
178
|
+
... print(f"{name}: {qty}")
|
|
179
|
+
"""
|
|
180
|
+
search_term = search_term.lower().strip()
|
|
181
|
+
return [(name, qty) for name, qty in self.measurements.items()
|
|
182
|
+
if search_term in name]
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class UnitParser:
|
|
186
|
+
"""
|
|
187
|
+
Natural language parser for units and measurements.
|
|
188
|
+
|
|
189
|
+
This class can extract units and quantities from natural language text
|
|
190
|
+
and convert them to Quantity objects.
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
def __init__(self, measurement_db: MeasurementDatabase | None = None) -> None:
|
|
194
|
+
self.measurement_db = measurement_db or MeasurementDatabase()
|
|
195
|
+
|
|
196
|
+
# Common unit patterns
|
|
197
|
+
self.unit_patterns = {
|
|
198
|
+
# Volume patterns
|
|
199
|
+
r"liters?|l|ml|milliliters?|cl|centiliters?|dl|deciliters?|hl|hectoliters?",
|
|
200
|
+
r"gallons?|gal|quarts?|pts?|pints?|cups?|tablespoons?|tbsp|teaspoons?|tsp",
|
|
201
|
+
|
|
202
|
+
# Mass patterns
|
|
203
|
+
r"kilograms?|kg|grams?|g|milligrams?|mg|micrograms?|µg|tonnes?|tons?",
|
|
204
|
+
|
|
205
|
+
# Length patterns
|
|
206
|
+
r"meters?|m|centimeters?|cm|millimeters?|mm|kilometers?|km|miles?|mi|feet|ft|inches?|in",
|
|
207
|
+
|
|
208
|
+
# Time patterns
|
|
209
|
+
r"seconds?|s|minutes?|min|hours?|h|days?|weeks?|months?|years?",
|
|
210
|
+
|
|
211
|
+
# Temperature patterns
|
|
212
|
+
r"celsius|c|fahrenheit|f|kelvin|k",
|
|
213
|
+
|
|
214
|
+
# Speed patterns
|
|
215
|
+
r"meters? per second|m/s|km/h|mph|knots?",
|
|
216
|
+
|
|
217
|
+
# Energy patterns
|
|
218
|
+
r"joules?|j|calories?|cal|kilocalories?|kcal|watt hours?|wh|kilowatt hours?|kwh",
|
|
219
|
+
|
|
220
|
+
# Power patterns
|
|
221
|
+
r"watts?|w|kilowatts?|kw|megawatts?|mw|horsepower|hp",
|
|
222
|
+
|
|
223
|
+
# Pressure patterns
|
|
224
|
+
r"pascals?|pa|bars?|atm|atmospheres?|torr|psi",
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
def parse_quantity(self, text: str) -> Quantity | None:
|
|
228
|
+
"""
|
|
229
|
+
Parse a quantity from natural language text.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
text: The text to parse
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
A Quantity object if a valid quantity is found, None otherwise
|
|
236
|
+
|
|
237
|
+
Examples:
|
|
238
|
+
>>> parser = UnitParser()
|
|
239
|
+
>>> qty = parser.parse_quantity("5 meters")
|
|
240
|
+
>>> print(qty)
|
|
241
|
+
5.0 meter
|
|
242
|
+
|
|
243
|
+
>>> qty = parser.parse_quantity("100 km/h")
|
|
244
|
+
>>> print(qty)
|
|
245
|
+
100.0 kilometer/hour
|
|
246
|
+
"""
|
|
247
|
+
text = text.strip().lower()
|
|
248
|
+
|
|
249
|
+
# Try to match number + unit pattern (allow spaces in unit names for compound units and scientific notation)
|
|
250
|
+
quantity_pattern = r"([0-9]+\.?[0-9]*[eE][+-]?[0-9]+|[0-9]+\.?[0-9]*)\s*([a-zA-Z/°µ\s]+)"
|
|
251
|
+
match = re.search(quantity_pattern, text)
|
|
252
|
+
|
|
253
|
+
if match:
|
|
254
|
+
value = float(match.group(1))
|
|
255
|
+
unit_str = match.group(2)
|
|
256
|
+
|
|
257
|
+
# Clean up the unit string - preserve slashes for compound units
|
|
258
|
+
unit_str = unit_str.replace("°", " degree ")
|
|
259
|
+
|
|
260
|
+
# Convert common plural units to singular and handle compound units
|
|
261
|
+
unit_mapping = {
|
|
262
|
+
"meters": "meter",
|
|
263
|
+
"kilometers": "kilometer",
|
|
264
|
+
"centimeters": "centimeter",
|
|
265
|
+
"millimeters": "millimeter",
|
|
266
|
+
"grams": "gram",
|
|
267
|
+
"kilograms": "kilogram",
|
|
268
|
+
"milligrams": "milligram",
|
|
269
|
+
"seconds": "second",
|
|
270
|
+
"minutes": "minute",
|
|
271
|
+
"hours": "hour",
|
|
272
|
+
"liters": "liter",
|
|
273
|
+
"milliliters": "milliliter",
|
|
274
|
+
"watts": "watt",
|
|
275
|
+
"kilowatts": "kilowatt",
|
|
276
|
+
"volts": "volt",
|
|
277
|
+
"amperes": "ampere",
|
|
278
|
+
"ohms": "ohm",
|
|
279
|
+
"hertz": "hertz",
|
|
280
|
+
"newtons": "newton",
|
|
281
|
+
"pascals": "pascal",
|
|
282
|
+
"joules": "joule",
|
|
283
|
+
"coulombs": "coulomb",
|
|
284
|
+
"farads": "farad",
|
|
285
|
+
"henrys": "henry",
|
|
286
|
+
"teslas": "tesla",
|
|
287
|
+
"webers": "weber",
|
|
288
|
+
"lumens": "lumen",
|
|
289
|
+
"luxes": "lux",
|
|
290
|
+
"becquerels": "becquerel",
|
|
291
|
+
"grays": "gray",
|
|
292
|
+
"sieverts": "sievert",
|
|
293
|
+
"katals": "katal",
|
|
294
|
+
"miles": "mile",
|
|
295
|
+
"feet": "foot",
|
|
296
|
+
"inches": "inch",
|
|
297
|
+
"yards": "yard",
|
|
298
|
+
"gallons": "gallon",
|
|
299
|
+
"pounds": "pound",
|
|
300
|
+
"ounces": "ounce",
|
|
301
|
+
# Compound units
|
|
302
|
+
"km/h": "kilometer/hour",
|
|
303
|
+
"kmh": "kilometer/hour",
|
|
304
|
+
"m/s": "meter/second",
|
|
305
|
+
"ms": "meter/second",
|
|
306
|
+
"mph": "mile/hour",
|
|
307
|
+
"knots": "knot",
|
|
308
|
+
"km": "kilometer", # Handle km without /h
|
|
309
|
+
"hrs": "hour", # Alternative for hours
|
|
310
|
+
"l": "liter", # Alternative for liter
|
|
311
|
+
"hr": "hour", # Abbreviation for hour
|
|
312
|
+
"meters per second squared": "meter_per_second_squared",
|
|
313
|
+
"meters/second squared": "meter_per_second_squared",
|
|
314
|
+
"meters per second^2": "meter_per_second_squared",
|
|
315
|
+
"meters/second^2": "meter_per_second_squared",
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
# Store original unit string for display purposes
|
|
319
|
+
original_unit_str = unit_str
|
|
320
|
+
|
|
321
|
+
# Apply unit mapping for internal processing
|
|
322
|
+
if unit_str in unit_mapping:
|
|
323
|
+
unit_str = unit_mapping[unit_str]
|
|
324
|
+
|
|
325
|
+
try:
|
|
326
|
+
# Create quantity with singular unit for internal processing
|
|
327
|
+
quantity = Quantity(value, unit_str)
|
|
328
|
+
# Preserve original unit string for display
|
|
329
|
+
quantity.unit = original_unit_str
|
|
330
|
+
return quantity
|
|
331
|
+
except ValueError:
|
|
332
|
+
# Unit not recognized, try to find it in our patterns
|
|
333
|
+
pass
|
|
334
|
+
|
|
335
|
+
# Try to find known objects
|
|
336
|
+
for object_name, quantity in self.measurement_db.measurements.items():
|
|
337
|
+
if object_name in text.lower():
|
|
338
|
+
return quantity
|
|
339
|
+
|
|
340
|
+
return None
|
|
341
|
+
|
|
342
|
+
def extract_quantities(self, text: str) -> list[Quantity]:
|
|
343
|
+
"""
|
|
344
|
+
Extract all quantities from a text.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
text: The text to analyze
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
List of Quantity objects found in the text
|
|
351
|
+
|
|
352
|
+
Examples:
|
|
353
|
+
>>> parser = UnitParser()
|
|
354
|
+
>>> quantities = parser.extract_quantities("A car traveling at 100 km/h for 2 hours")
|
|
355
|
+
>>> for qty in quantities:
|
|
356
|
+
... print(qty)
|
|
357
|
+
"""
|
|
358
|
+
quantities = []
|
|
359
|
+
|
|
360
|
+
# Use regex to find all quantity patterns in the text
|
|
361
|
+
# This pattern matches numbers followed by units (with optional whitespace)
|
|
362
|
+
quantity_pattern = re.compile(r'(\d+\.?\d*)\s*([a-zA-Z/]+)')
|
|
363
|
+
|
|
364
|
+
for match in quantity_pattern.finditer(text):
|
|
365
|
+
value_str, unit_str = match.groups()
|
|
366
|
+
try:
|
|
367
|
+
value = float(value_str)
|
|
368
|
+
# Try to parse this specific quantity
|
|
369
|
+
quantity = self.parse_quantity(f"{value} {unit_str}")
|
|
370
|
+
if quantity:
|
|
371
|
+
quantities.append(quantity)
|
|
372
|
+
except (ValueError, AttributeError):
|
|
373
|
+
# Skip invalid quantities
|
|
374
|
+
continue
|
|
375
|
+
|
|
376
|
+
return quantities
|
|
377
|
+
|
|
378
|
+
def find_units_in_text(self, text: str) -> list[str]:
|
|
379
|
+
"""
|
|
380
|
+
Find all unit references in text.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
text: The text to analyze
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
List of unit strings found in the text
|
|
387
|
+
|
|
388
|
+
Examples:
|
|
389
|
+
>>> parser = UnitParser()
|
|
390
|
+
>>> units = parser.find_units_in_text("The speed is 5 m/s and pressure is 1013 hPa")
|
|
391
|
+
>>> print(units)
|
|
392
|
+
['meter/second', 'hectopascal']
|
|
393
|
+
"""
|
|
394
|
+
units_found = []
|
|
395
|
+
text_lower = text.lower()
|
|
396
|
+
|
|
397
|
+
# Check for known units from our database
|
|
398
|
+
all_units: set[str] = set()
|
|
399
|
+
all_units.update(UnitSystem.BASE_UNITS.keys())
|
|
400
|
+
all_units.update(UnitSystem.DERIVED_UNITS.keys())
|
|
401
|
+
|
|
402
|
+
# Also include common unit abbreviations
|
|
403
|
+
unit_abbreviations = {
|
|
404
|
+
'hpa': 'hectopascal',
|
|
405
|
+
'c': 'celsius',
|
|
406
|
+
'f': 'fahrenheit',
|
|
407
|
+
'k': 'kelvin',
|
|
408
|
+
'm': 'meter',
|
|
409
|
+
's': 'second',
|
|
410
|
+
'kg': 'kilogram',
|
|
411
|
+
'g': 'gram',
|
|
412
|
+
'l': 'liter',
|
|
413
|
+
'ml': 'milliliter',
|
|
414
|
+
'km': 'kilometer',
|
|
415
|
+
'cm': 'centimeter',
|
|
416
|
+
'mm': 'millimeter',
|
|
417
|
+
'h': 'hour',
|
|
418
|
+
'min': 'minute',
|
|
419
|
+
'pa': 'pascal',
|
|
420
|
+
'kpa': 'kilopascal',
|
|
421
|
+
'mpa': 'megapascal',
|
|
422
|
+
'bar': 'bar',
|
|
423
|
+
'psi': 'psi',
|
|
424
|
+
'atm': 'atmosphere',
|
|
425
|
+
'w': 'watt',
|
|
426
|
+
'kw': 'kilowatt',
|
|
427
|
+
'j': 'joule',
|
|
428
|
+
'kj': 'kilojoule',
|
|
429
|
+
'v': 'volt',
|
|
430
|
+
'a': 'ampere',
|
|
431
|
+
'ohm': 'ohm',
|
|
432
|
+
'hz': 'hertz',
|
|
433
|
+
'khz': 'kilohertz',
|
|
434
|
+
'mhz': 'megahertz',
|
|
435
|
+
'ghz': 'gigahertz',
|
|
436
|
+
'nm': 'nanometer',
|
|
437
|
+
'um': 'micrometer',
|
|
438
|
+
'm/s': 'meter/second',
|
|
439
|
+
'km/h': 'kilometer/hour',
|
|
440
|
+
'mph': 'mile/hour',
|
|
441
|
+
'rpm': 'revolution/minute'
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
# Check for full unit names first (using word boundaries)
|
|
445
|
+
import re
|
|
446
|
+
for unit in all_units:
|
|
447
|
+
# Use word boundary regex to avoid substring matches
|
|
448
|
+
if re.search(r'\b' + re.escape(unit) + r'\b', text_lower):
|
|
449
|
+
units_found.append(unit)
|
|
450
|
+
|
|
451
|
+
# Check for unit abbreviations (using word boundaries)
|
|
452
|
+
for abbr, full_unit in unit_abbreviations.items():
|
|
453
|
+
if re.search(r'\b' + re.escape(abbr) + r'\b', text_lower) and full_unit not in units_found:
|
|
454
|
+
units_found.append(full_unit)
|
|
455
|
+
|
|
456
|
+
return units_found
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
# Global instance for convenience
|
|
460
|
+
default_measurement_db = MeasurementDatabase()
|
|
461
|
+
default_parser = UnitParser(default_measurement_db)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def get_measurement(object_name: str) -> Quantity | None:
|
|
465
|
+
"""
|
|
466
|
+
Convenience function to get a measurement from the default database.
|
|
467
|
+
|
|
468
|
+
Args:
|
|
469
|
+
object_name: The name of the object to look up
|
|
470
|
+
|
|
471
|
+
Returns:
|
|
472
|
+
The Quantity object if found, None otherwise
|
|
473
|
+
"""
|
|
474
|
+
return default_measurement_db.get_measurement(object_name)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def parse_quantity(text: str) -> Quantity | None:
|
|
478
|
+
"""
|
|
479
|
+
Convenience function to parse a quantity from text.
|
|
480
|
+
|
|
481
|
+
Args:
|
|
482
|
+
text: The text to parse
|
|
483
|
+
|
|
484
|
+
Returns:
|
|
485
|
+
A Quantity object if a valid quantity is found, None otherwise
|
|
486
|
+
"""
|
|
487
|
+
return default_parser.parse_quantity(text)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def extract_quantities(text: str) -> list[Quantity]:
|
|
491
|
+
"""
|
|
492
|
+
Convenience function to extract quantities from text.
|
|
493
|
+
|
|
494
|
+
Args:
|
|
495
|
+
text: The text to analyze
|
|
496
|
+
|
|
497
|
+
Returns:
|
|
498
|
+
List of Quantity objects found in the text
|
|
499
|
+
"""
|
|
500
|
+
return default_parser.extract_quantities(text)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def find_units_in_text(text: str) -> list[str]:
|
|
504
|
+
"""
|
|
505
|
+
Convenience function to find units in text.
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
text: The text to analyze
|
|
509
|
+
|
|
510
|
+
Returns:
|
|
511
|
+
List of unit strings found in the text
|
|
512
|
+
"""
|
|
513
|
+
return default_parser.find_units_in_text(text)
|