首页 > 解决方案 > 使用否定集 [^] 和什么?否定同一行中的子字符串

问题描述

我正在编写一个解析器,而不是将LaTeX数学转换为与 pythoneval()兼容的字符串。

我到了一个点,我有一个看起来像这样的字符串:

\sqrt{4m/s} - \frac{3v+10.5v}{20a-8a} +1/2

注意仍然主要是LaTeX语法,以及一些任意的“单位”字母。然后我使用下面的否定集来替换除否定集中的所有内容。

    mathstr = re.sub('[^0-9*()/+\-.Q]','',mathstr)

如何包含子字符串“sqrt”,以便它可以以类似的方式工作,最好是在相同的正则表达式中?

现在我的工作是用' \sqrt'替换' Q',执行上面的代码行,然后将' Q'设置为' sqrt'之后,我从上述语法到eval()语法的完整例程如下:

    mathstr = mathstr.replace(" ","")
    if pwrRe.search(mathstr):
        mathstr = re.sub(pwrRe,'**',mathstr)
    if MultiplyRe.search(mathstr):
        mathstr = re.sub(MultiplyRe,'*',mathstr)
    if DivideRe.search(mathstr) or sqrtRe.search(mathstr):
        mathstr = re.sub('\\\\frac{','(',mathstr)
        mathstr = re.sub('\\\\sqrt{','\\\\sqrt(',mathstr)   
        mathstr = re.sub('}{',')/(',mathstr)
        mathstr = re.sub('}',')',mathstr)
    mathstr = re.sub('[/*+\-^][a-zA-Z]','',mathstr)
    mathstr = re.sub('\\\\sqrt','Q',mathstr)
    mathstr = re.sub('[^0-9*()/+\-.Q]','',mathstr)
    mathstr = re.sub(r'Q','sqrt',mathstr)

这导致eval()语法:

sqrt(4)-(3+10.5)/(20-8)+1/2

但这很草率,如果我可以在一行中将字符和子字符串“列入白名单”,从而消除所有其他出现的字符,那么它在许多领域都会很有用。

编辑:

随着我继续扩展我的脚本,这个列表会变得更长,但现在我想匹配以下内容并丢弃其他所有内容:

0123456789()/*+-^sqrt <-- only sqrt when it's a substring

这里有一些例子:

Before: sqrt(5s+2s)+(3s**2/9s)
After: sqrt(5+2)+(3**2/9)

Before: sqrt(4*(5+2)/(2))\$
After:  sqrt(4*(5+2)/(2))

Before: sqrt(4v/a)-(3v+10.5v)/(20a-8a)+1/2ohms
After:  sqrt(4)-(3+10.5)/(20-8)+1/2

除了仅匹配这些字符之外,还有一些细微差别。在我的第一个示例中,您可以看到我有 v/a,即使那里有一个“/”,我也将其删除。

标签: pythonregexparsing

解决方案


与其“删除”指定的字符,不如“保留”指定的字符——这容易,因为您已经否定了该组:

[0-9*()/+\-.Q]

然后你可以添加任何你想要的替代文字,例如:

[0-9*()/+\-.Q]|sqrt

在 Python 中,这可能看起来像,使用joinand re.findall()

tests = [
    ('sqrt(5s+2s)+(3s**2/9s)', 'sqrt(5+2)+(3**2/9)'),
    ('sqrt(4*(5+2)/(2))\$', 'sqrt(4*(5+2)/(2))'),
    ('sqrt(4v/a)-(3v+10.5v)/(20a-8a)+1/2ohms)', 'sqrt(4)-(3+10.5)/(20-8)+1/2')
]

import re

for (before, expected) in tests:
    matches = re.findall(r"[0-9*()/+\-.Q]|sqrt", before)
    after = ''.join(matches)

    is_ok = (after == expected)
    print(after, is_ok, '' if is_ok else expected)

输出:

sqrt(5+2)+(3**2/9) 真
sqrt(4*(5+2)/(2)) 真
sqrt(4/)-(3+10.5)/(20-8)+1/2) 错误 sqrt(4)-(3+10.5)/(20-8)+1/2

(由于第一个正斜杠,最后一个与您的期望不匹配,但这确实超出了问题的范围。)


推荐阅读