Python正则表达式解析餐厅销售数据分组错误排查求助
正则表达式解析餐厅销售数据分组错误解决
问题详情
我用Python正则表达式提取PDF中的餐厅销售样本数据并转换为JSON格式,当前使用的正则表达式为:
^\s*(\d+)\s*(([A-Za-z]+\s*)+)?(\d+)\s+(.+?)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)$
当解析样本字符串:
1 NA BEVERAGE 1100 ICED TEA 14.00 3.00 42.00 3.50 0.00 42.00 0.00 0.52 47.09
时,得到错误的分组结果:
{'item_category': 'NA BEVERAGE ', 'item_number': 'BEVERAGE '}
正确结果应为:
{'item_category': 'NA BEVERAGE ', 'item_number':'1100'}
期望的完整正确JSON输出:
{ "item_rank": "1", "item_category": "NA BEVERAGE ", "item_number": "1100", "item_name": "ICED TEA", "number_sold": "14.00", "price_sold": "3.00", "amount": "42.00", "tax": "3.50", "cost": "0.00", "profit": "42.00", "food_cost": "0.00", "precent_sales": "0.52", "cat_sales": "47.09" }
可复现的原始代码:
import re import json page_text_str = " 1 NA BEVERAGE 1100 ICED TEA 14.00 3.00 42.00 3.50 0.00 42.00 0.00 0.52 47.09" sale_line_re = re.compile('^\s*(\d+)\s*(([A-Za-z]+\s*)+)?(\d+)\s+(.+?)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)\s+(\d+.\d+)$') grouped_data = [] for line in page_text_str.split('\n'): print(line) match = sale_line_re.match(line) if match: groups = match.groups() item = { "item_rank": groups[0], "item_category": groups[1], "item_number": groups[2], "item_name": groups[3], "number_sold": groups[4], "price_sold": groups[5], "amount": groups[6], "tax": groups[7], "cost": groups[8], "profit": groups[9], "food_cost": groups[10], "precent_sales": groups[11], "cat_sales": groups[12] } grouped_data.append(item) for sale in grouped_data: print(sale)
问题原因
- 分组索引错误:原正则中
(([A-Za-z]+\s*)+)?是嵌套分组,内部的([A-Za-z]+\s*)会捕获分组内最后一次匹配的内容(也就是BEVERAGE),而完整的分类文本是外部分组groups[1]。但代码里错误地将groups[2](内部分组)赋值给了item_number,正确的item_number应该是后续的groups[3]。 - 未转义小数点:原表达式中
\d+.\d+的.是正则元字符,会匹配任意字符,应该转义为\d+\.\d+才能精准匹配小数格式。 - 分组顺序对应错误:后续的数值字段索引全部错位,导致所有数值字段都对应到了错误的分组。
修正方案
1. 修正正则表达式
转义小数点,确保匹配小数的准确性,正则表达式调整为:
^\s*(\d+)\s*(([A-Za-z]+\s*)+)?(\d+)\s+(.+?)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)$
2. 修正代码分组索引
调整item_number及后续字段的分组索引,对应正确的捕获组:
item_number对应groups[3]item_name对应groups[4]- 后续数值字段依次对应
groups[5]到groups[13]
修正后的完整代码
import re import json page_text_str = " 1 NA BEVERAGE 1100 ICED TEA 14.00 3.00 42.00 3.50 0.00 42.00 0.00 0.52 47.09" # 转义小数点,确保小数匹配精准 sale_line_re = re.compile(r'^\s*(\d+)\s*(([A-Za-z]+\s*)+)?(\d+)\s+(.+?)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)$') grouped_data = [] for line in page_text_str.split('\n'): print(line) match = sale_line_re.match(line) if match: groups = match.groups() item = { "item_rank": groups[0], # 可选:去除分类文本末尾多余空格 "item_category": groups[1].strip() if groups[1] else None, "item_number": groups[3], "item_name": groups[4], "number_sold": groups[5], "price_sold": groups[6], "amount": groups[7], "tax": groups[8], "cost": groups[9], "profit": groups[10], "food_cost": groups[11], "precent_sales": groups[12], "cat_sales": groups[13] } grouped_data.append(item) # 格式化输出JSON for sale in grouped_data: print(json.dumps(sale, indent=2))
运行修正后的代码,即可得到期望的正确输出。
内容的提问来源于stack exchange,提问作者Pythonic Crow
相关产品推荐
相关产品推荐

