我们可以通过两步替换来实现:
import re
str = "$rac{some}{latex}$$$\int^e_v {en} more$$\$rac{some}{latex}$$$\int^e_v {en} more$$\n$rac{some}{latex}$\n$$\int^e_v {en} more$$\n\$rac{some}{latex}$\n$$\int^e_v {en} more$$"
#first step:
str = re.sub(r'(?<![\\])\$\$([^\$]+)\$\$', "<div>$$\g<1>$$</div>", str)
#second step:
str = re.sub(r'(?<![\$\\])\$([^\$]+)(?:(?<!\<div\>)(?<!\\)\$)', "<span>$\g<1>$</span>", str)
print str
解释:
第一步:
我们仅在出现$$ 时执行替换,将其替换为<div>$$\g<1>$$</div>(\g<1> 将替换为正则表达式中定义的第一个组)。
str = re.sub(r'(?<![\\])\$\$([^\$]+)\$\$', "<div>$$\g<1>$$</div>", str)
意识到我们正在使用这个 regex (?<![\\])\$\$([^\$]+)\$\$ regex101 example,它的工作方式如下:
-
(?<![\\]) ... 定义我们正在匹配... 前面没有\ [在正则表达式中:(?<![\\])]。所以首先我们说我们不想在表达式前加上\。
-
... \$\$ ... 定义我们必须在字符串的开头出现 $$。
-
... ([^\$]+) 定义我们想要除上一步之后的 $ 之外的所有内容[在正则表达式中 [^\$]+]。然后我们把它放到一个捕获组(...),供以后在代码中引用。
-
... \$\$ 毕竟我们完成了表达式,说我们必须在字符串的最后出现$$。
第二步:
我们仅在出现$ 时执行替换,将其替换为<span>$\g<1>$</span>(同样,\g<1> 将被正则表达式中定义的第一个组匹配替换)
str = re.sub(r'(?<![\$\\])\$([^\$]+)(?:(?<!\<div\>)(?<!\\)\$)', "<span>$\g<1>$</span>", str)
还要意识到我们正在使用另一个 regex (?<![\$\\])\$([^\$]+)(?:(?<!\<div\>)(?<!\\)\$)(是的,有点难)regex101 example,其工作方式如下:
-
(?<![\$\\]) ... 定义我们匹配 ... 之前没有 \ 或 $ [在正则表达式中:(?<![\\\$])]。所以首先我们说我们一开始不想要\ 或$。
-
... \$ ... 定义我们的字符串需要以一个 $ 开头
-
... ([^\$]+) ... 定义一个捕获组,其中包含除 $ 之外的所有内容,以供将来回调。
-
... (?:(?<!\<div\>)(?<!\\)\$) 我们说完我们的字符串以 $ 结尾,但前面没有 div [在正则表达式中:?<!\<div\>)] 或 \ [在正则表达式中: (?<!\\)]。 (然后我们把它全部放到一个非捕获组中说这一切都只是一件事(?:(?<!\<div\>)(?<!\\)\$))
注意:也许有更有效的方法可以得到这个结果。