如何用正则表达式化简含参运算字符串:移除零项并合并常数项
化简含参数M的运算字符串实现方案
需求背景
现有如下Python代码中的运算字符串:
import re # 含参数M的运算字符串 z_j_func = 'Z = 1 * 0 + 4 * 1/2 + 0 * 0 + 3 / 2 + M * 12 + M * 12 + M * 2 - 4 / 8'
需要完成两步化简操作:
- 计算所有不含参数M的项的结果,得到中间状态:
z_j_func = 'Z = 0 + 2 + 0 + 3 / 2 + M * 12 + M * 12 + M * 2 - 1 / 2'
- 移除值为0的项,并合并可运算的常数项,最终得到:
z_j_func = 'Z = 3 + M * 12 + M * 12 + M * 2'
实现步骤与代码
核心思路是用正则表达式区分不含M的常数运算项和含M的项,分别处理后再合并结果。
第一步:计算所有无M的项
通过正则匹配所有不含M的运算片段,调用eval计算结果后替换回原字符串:
import re z_j_func = 'Z = 1 * 0 + 4 * 1/2 + 0 * 0 + 3 / 2 + M * 12 + M * 12 + M * 2 - 4 / 8' # 计算单个常数项的结果 def calc_constant(match): expr = match.group().replace(' ', '') # 去除空格,适配eval语法 res = eval(expr) # 保持原有的符号格式 if res >= 0 and match.group().startswith(('+', ' ')): return f' + {res}' return f' {res}' # 替换开头的常数项(无前置符号) z_j_mid = re.sub(r'^Z = (\d+(?:\s*[*/]\s*\d+)*)', lambda m: f'Z = {eval(m.group(1).replace(" ", ""))}', z_j_func) # 替换其余带+/-的常数项 pattern = re.compile(r'(?<=Z = |[+-] )\d+(?:\s*[*/]\s*\d+)*') z_j_mid = pattern.sub(calc_constant, z_j_mid) # 此时z_j_mid为中间状态:"Z = 0 + 2 + 0 + 1.5 + M * 12 + M * 12 + M * 2 - 0.5"
第二步:移除0项并合并常数项
拆分所有项,分离常数项和含M的项,累加常数项后重新拼接:
# 拆分所有项和对应的符号 items = re.split(r'\s*[+-]\s*', z_j_mid.replace('Z = ', '')) signs = ['+'] + re.findall(r'[+-]', z_j_mid.replace('Z = ', '')) constant_total = 0 m_term_list = [] for sign, item in zip(signs, items): item = item.strip() if 'M' in item: # 保留含M的项及符号 m_term_list.append(f'{sign} {item}') else: # 累加常数项 val = float(item) constant_total += val if sign == '+' else -val # 处理常数项的显示(整数形式优先) constant_part = '' if constant_total != 0: if constant_total.is_integer(): constant_part = f'{int(constant_total)}' else: constant_part = f'{constant_total}' # 拼接最终结果 final_parts = [] if constant_part: final_parts.append(constant_part) final_parts.extend(m_term_list) # 移除开头多余的+号 if final_parts and final_parts[0].startswith('+'): final_parts[0] = final_parts[0][2:] z_j_final = f'Z = {" + ".join(final_parts)}' print(z_j_final) # 输出:Z = 3 + M * 12 + M * 12 + M * 2
正则表达式说明
匹配无M的常数项:
^Z = (\d+(?:\s*[*/]\s*\d+)*):匹配字符串开头的常数运算项(如1 * 0)(?<=Z = |[+-] )\d+(?:\s*[*/]\s*\d+)*:匹配带+/-前缀的常数运算项(如4 * 1/2),通过正向预查确保前缀合法
拆分项与符号:
re.split(r'\s*[+-]\s*', ...):用带空格的+/-作为分隔符拆分所有项re.findall(r'[+-]', ...):提取所有项的符号,用于常数项的累加计算
可选:保留分数形式
如果需要保留分数而非浮点数,可改用fractions.Fraction处理:
from fractions import Fraction def calc_constant(match): expr = match.group().replace(' ', '') res = Fraction(expr) if res >= 0 and match.group().startswith(('+', ' ')): return f' + {res}' return f' {res}'
此方式下中间状态会保留3/2、1/2等分数形式,最终合并后仍会得到整数3。
内容的提问来源于stack exchange,提问作者Elektvocal95
相关产品推荐
相关产品推荐

