文本转十进制数值:解决‘three and half’场景的转换问题
解决英文数量词带分数的识别问题
现有Python代码可将文本中的英文数量词(如“three”)转换为十进制数值,但无法处理“three and half”这类带分数的表述,导致番茄的数量被错误识别为0.5,需要优化代码以正确转换为3.5。
输入示例
"Please get me a three and half of tomato and one bottle of milk, 3 kilos of carrots and half kilo of beans finally 1 bottle water, thank you"
当前错误输出
Shopping list: 1 bottle milk 3.0 kilo carrots 0.5 kilo tomato 1.0 bottle water 0.5 kilo beans
期望输出
Shopping list: 1 bottle milk 3.0 kilo carrots 3.5 kilo tomato 1.0 bottle water 0.5 kilo beans
解决方案
核心需修改两个部分:正则表达式以匹配带分数的数量结构,以及数量转换函数以处理组合式的数量计算。
修改步骤
- 更新正则表达式:新增匹配
数字/数量词 + and + half/quarter的结构,确保捕获完整的带分数表述 - 扩展数量转换函数:处理捕获到的组合数量,将整数部分和分数部分相加得到正确数值
- 调整匹配结果处理逻辑:针对单独数量、组合数量两种匹配结果进行对应转换
修改后的完整代码
import re from collections import OrderedDict products = { "milk": ["milk"], "carrots": ["carrot", "carrots"], "tomato": ["tomato", "tomatoes"], "water": ["water"], "beans": ["beans"] # 可添加更多产品 } def convert_to_decimal(quantity_parts): # 处理组合数量(如("three", "half")) if isinstance(quantity_parts, tuple): integer_part = quantity_parts[0].lower() fraction_part = quantity_parts[1].lower() words_to_numbers = { 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10 } integer_val = words_to_numbers.get(integer_part, 0.0) if not integer_part.isdigit() else float(integer_part) fraction_val = {'half': 0.5, 'quarter': 0.25}[fraction_part] return integer_val + fraction_val # 处理单独数量 quantity_text = quantity_parts.lower() if quantity_text in ['half', 'quarter']: return {'half': 0.5, 'quarter': 0.25}[quantity_text] elif quantity_text.isdigit(): return float(quantity_text) else: words_to_numbers = { 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10 } return words_to_numbers.get(quantity_text, 0.0) def create_shopping_list(text): items = OrderedDict() for product, keywords in products.items(): for keyword in keywords: # 正则表达式:匹配两种情况:1. 单独数量词/数字;2. 数量词/数字 + and + half/quarter pattern = fr'((\d+(?:\.\d+)?|\b(?:one|two|three|four|five|six|seven|eight|nine|ten)\b)\s+and\s+(half|quarter)|\b(?:half|quarter|one|two|three|four|five|six|seven|eight|nine|ten)\b|\d+(?:\.\d+)?)' \ fr'\s*(?:bottle|kilo)?s?\s*(?:of\s*)?{keyword}' matches = re.findall(pattern, text, re.IGNORECASE) for match in matches: # 提取有效匹配:如果是组合结构,取第2、3组;否则取第0组 if match[1] and match[2]: quantity = convert_to_decimal((match[1], match[2])) else: quantity = convert_to_decimal(match[0]) items.setdefault(product, set()).add(quantity) result = [] for product, quantities in items.items(): for quantity in quantities: # 根据产品类型设置单位 unit = 'bottle' if product in ['milk', 'water'] else 'kilo' result.append(f"{quantity} {unit} {product}") # 去重并保留顺序 unique_shopping_list = list(dict.fromkeys(result)) return unique_shopping_list # 示例使用 user_input = "Please get me three and half kilo of tomato and one bottle of milk, 3 kilos of carrots and half kilo of beans finally 1 bottle water, thank you" shopping_list = create_shopping_list(user_input) if shopping_list: print("Shopping list:") for item in shopping_list: print(item) else: print("No items found in the input.")
关键修改说明
- 正则表达式:新增
(\d+(?:\.\d+)?|\b(?:one|...|ten)\b)\s+and\s+(half|quarter)分支,捕获带and的分数组合,同时保留原有单独数量的匹配逻辑 - convert_to_decimal函数:新增元组类型参数处理逻辑,当传入整数部分和分数部分的元组时,分别转换后相加得到最终数值
- 匹配结果处理:遍历匹配结果时,判断是否为组合结构,将对应部分传入转换函数
内容的提问来源于stack exchange,提问作者david gamal
相关产品推荐
相关产品推荐

