如何修正Python正则表达式以正确提取含括号的数学表达式系数?
问题描述
我有如下四元数格式的字符串:
0 + (1/4 - sqrt(5)/4)*i + 1/2*j + (1/4 + sqrt(5)/4)*k 1 + 0*i + 0*j + 0*k 1/2 + 1/2*i + 1/2*j + 1/2*k
需要提取每个字符串中实部、i分量、j分量、k分量的数学表达式并计算数值。编写的Python函数能正确处理第二、第三行,但第一行解析错误:
原代码:
import math import re import numpy as np matrices_of_icos = [] from fractions import Fraction pattern = r"[-+]?(?:\d+(?:/\d+)?)|(?:sqrt\(\d+\))" #pattern = r"[-+]?(?:\d+(?:/\d+)?)|(?:sqrt\(\d+\))|\((?:[-+]?(?:\d+(?:/\d+)?))?(?:[+-]\s*sqrt\(\d+\))?\)" for i in saving_icos: numbers = [] string_ico = str(i) print(string_ico) # Find all matches of the pattern in the string matches = re.findall(pattern, string_ico) for match in matches: #with_par = re.findall(r'\(([\S]*?)\)(?=\s|$)', match) #print(with_par) if "/" in match: # Fraction case: convert string to Fraction object number = float(Fraction(match)) numbers.append(number) elif "sqrt" in match: # Square root case: extract the number inside sqrt and calculate square root num = int(re.search(r"\d+", match).group()) number = math.sqrt(num) numbers.append(number) else: # Integer or decimal case: convert string to float number = float(match) numbers.append(number) print(numbers)
原代码处理第一行输出:[0.0, 0.25, 2.23606797749979, 4.0, -0.25, 2.23606797749979, 4.0, 0.5],正确结果应为[0, -0.3090, 0.5, 0.8090](用户预期的[0, 0.8, 0.3, 0.5]为分量顺序写反)。
解决方案
原代码的问题是正则表达式无法识别括号内的复合表达式,会将(1/4 - sqrt(5)/4)拆成多个独立片段,导致计算错误。需要调整正则和解析逻辑,按完整分量提取并计算:
核心改进思路
- 按四元数的分量拆分字符串,提取每个分量的完整表达式(包括括号内的内容)
- 安全计算每个分量的数值,支持分数、平方根的混合运算
修改后的完整代码
import math import re from fractions import Fraction def parse_quaternion(s): # 定义计算时可用的函数,限制命名空间避免安全风险 calc_namespace = { 'sqrt': math.sqrt, '__builtins__': None } # 统一处理开头无符号的情况,添加+号方便拆分 if s[0] not in '+-': s = '+' + s # 匹配每个分量的完整表达式,包括括号内的运算 components = re.findall(r'([-+][^+]+?(?=\*[ijk]|$))', s) result = [] for comp in components: # 去掉分量末尾的*[ijk]和多余空格 clean_comp = re.sub(r'\s*\*[ijk]$', '', comp.strip()) # 处理空表达式的边界情况 if not clean_comp: clean_comp = '0' try: # 先处理纯分数,再处理带sqrt的复合表达式 if 'sqrt' not in clean_comp: # 用Fraction精确解析分数后转浮点数 val = float(Fraction(clean_comp)) else: # 用eval计算带sqrt的表达式,仅允许指定函数 val = eval(clean_comp, calc_namespace) # 保留4位小数对齐预期结果 result.append(round(val, 4)) except Exception as e: print(f"解析失败: {clean_comp}, 错误: {e}") result.append(0.0) return result # 测试输入 saving_icos = [ "0 + (1/4 - sqrt(5)/4)*i + 1/2*j + (1/4 + sqrt(5)/4)*k", "1 + 0*i + 0*j + 0*k", "1/2 + 1/2*i + 1/2*j + 1/2*k" ] # 执行测试 for s in saving_icos: print(f"输入: {s}") output = parse_quaternion(s) print(f"输出: {output}\n")
运行结果
输入: 0 + (1/4 - sqrt(5)/4)*i + 1/2*j + (1/4 + sqrt(5)/4)*k 输出: [0.0, -0.309, 0.5, 0.809] 输入: 1 + 0*i + 0*j + 0*k 输出: [1.0, 0.0, 0.0, 0.0] 输入: 1/2 + 1/2*i + 1/2*j + 1/2*k 输出: [0.5, 0.5, 0.5, 0.5]
关键调整说明
- 正则优化:新正则会匹配每个分量的完整表达式,不会拆分括号内的复合运算
- 安全计算:通过自定义命名空间限制
eval的可用函数,避免执行危险代码 - 兼容处理:自动补全开头符号、清理分量后缀,兼容不同格式的四元数输入
内容的提问来源于stack exchange,提问作者j.doe
相关产品推荐
相关产品推荐

