linux Perl函数替换Latex中的一般嵌套分数表达式

vbopmzt1  于 2023-06-05  发布在  Linux
关注(0)|答案(1)|浏览(167)

我有一个perl脚本,我使用它与bash脚本相结合,用一些Latex代码片段替换文件中的字符和一般嵌套分数。Perl脚本中控制分数替换的部分由以下函数给出:

sub process_latex {
    my ($latex) = @_;
    1 while $latex =~ s{
        \\frac
        \{
            ((?:[^{}]|(?R))*) # numerator (match balanced braces)
        \}
        \{
            ((?:[^{}]|(?R))*) # denominator (match balanced braces)
        \}
    }{
        my ($numerator, $denominator) = ($1, $2);
        $numerator = process_latex($numerator);
        $denominator = process_latex($denominator);
        "($numerator)/($denominator)";
    }gex;
    return $latex;
}

这个脚本可以成功地处理嵌套的分数表达式,这些表达式在任何深度的任何参数中都没有任何其他Latex命令。举个例子。使用这个脚本,我可以替换表达式

\frac{\frac{x11}{x12} x2}{\frac{y1}{y2 \frac{y31}{y32}} y4}
\frac{\frac{a1}{a2} \frac{b1}{b2}}{\frac{c1}{c2} \frac{d1}{d2}}

((x11)/(x12) x2)/((y1)/(y2 (y31)/(y32)) y4)
((a1)/(a2) (b1)/(b2))/((c1)/(c2) (d1)/(d2))

但它不适用于以下表达式

\frac{ \frac{1\frac{2}{3}}{4} a{} }{ b{} }
\frac{\epsilon+\gamma}{2^{-4\epsilon}}
\frac{\frac{1}{2} \textbf{a}}{b \textit{c}}

为此我应该

((1(2)/(3))/(4) a{} )/( b{} )
(\epsilon+\gamma)/(2^{-4\epsilon})
((1)/(2) \textbf{a})/(b \textit{c})

但结果却变成了

\frac{ (1(2)/(3))/(4) a{} }{ b{} }
\frac{\epsilon+\gamma}{2^{-4\epsilon}}
\frac{(1)/(2) \textbf{a}}{b \textit{c}}

我可以使用一些帮助来修改perl函数,以便正确替换Latex分数表达式,这些表达式可能在其参数中包含嵌套或链接的大括号对,例如\frac{a{}{}}{b}\frac{a}{b{{}}},其中ab是一些通用的Latex命令。

m528fe3b

m528fe3b1#

问题是(?R)递归整个模式,它需要\frac文本来开始匹配。一旦你替换了字符串中的一些\frac,你可能再也找不到匹配了。
因此,一个潜在的解决方案是只递归花括号之间的子字符串:

sub process_latex {
    my ($latex) = @_;
    1 while $latex =~ s{
        \\frac
        (\{
            ([^{}]*(?:(?1)[^{}]*)*) # numerator (match balanced braces)
        \})
        (\{
            ([^{}]*(?:(?3)[^{}]*)*) # denominator (match balanced braces)
        \})
    }{
        my ($numerator, $denominator) = ($2, $4);
        $numerator = process_latex($numerator);
        $denominator = process_latex($denominator);
        "($numerator)/($denominator)";
    }gex;
    return $latex;
}

参见this online demo
这里,((?:[^{}]|(?R))*)部分被([^{}]*(?:(?1)[^{}]*)*)([^{}]*(?:(?3)[^{}]*)*)替换,以仅递归必要的模式部分,并且相应地调整替换(($1, $2) => ($2, $4))。

相关问题