Javascript 如何使用正则表达式简化嵌套的大括号?

Javascript 如何使用正则表达式简化嵌套的大括号?,javascript,regex,Javascript,Regex,我试图简化LaTeX中嵌套的花括号 换句话说:{{…}}{{{…}}}等等。→ {…} 例如,TeX的一部分如下所示: $$\begin{aligned} \pi &= \frac{1}{2}\sum\limits_{k = 0}^\infty {\frac{1}{{{{16}^k}}}} \left( {\frac{8}{{8k + 2}} + \frac{4}{{8k + 3}} + \frac{4}{{8k + 4}} - \frac{1}{{8k + 7}}} \right)\\

我试图简化LaTeX中嵌套的花括号

换句话说:
{{…}
}
{{{…}}
}等等。→ <代码>{…}

例如,TeX的一部分如下所示:

$$\begin{aligned}
\pi &= \frac{1}{2}\sum\limits_{k = 0}^\infty {\frac{1}{{{{16}^k}}}} \left( {\frac{8}{{8k + 2}} + \frac{4}{{8k + 3}} + \frac{4}{{8k + 4}} - \frac{1}{{8k + 7}}} \right)\\
\zeta (2) &= \frac{{{\pi ^2}}}{6} = \frac{3}{{16}}\sum\limits_{k = 0}^\infty {\frac{1}{{{{64}^k}}}} \left( {\frac{{16}}{{{{(6k + 1)}^2}}} - \frac{{24}}{{{{(6k + 2)}^2}}} - \frac{8}{{{{(6k + 3)}^2}}} - \frac{6}{{{{(6k + 4)}^2}}} + \frac{1}{{{{(6k + 5)}^2}}}} \right)\\
\zeta (3) &= \frac{9}{{224}}\sum\limits_{k = 0}^\infty {\frac{1}{{{{4096}^k}}}}
\left(\begin{aligned} 
&\frac{{1024}}{{{{(24k + 2)}^3}}} - \frac{{3072}}{{{{(24k + 3)}^3}}} + \frac{{512}}{{{{(24k + 4)}^3}}} + \frac{{1024}}{{{{(24k + 6)}^3}}} + \frac{{1152}}{{{{(24k + 8)}^3}}}\\
+& \frac{{384}}{{{{(24k + 9)}^3}}} + \frac{{64}}{{{{(24k + 10)}^3}}} + \frac{{128}}{{{{(24k + 12)}^3}}} + \frac{{16}}{{{{(24k + 14)}^3}}} + \frac{{48}}{{{{(24k + 15)}^3}}} + \frac{{72}}{{{{(24k + 16)}^3}}}\\
+& \frac{{16}}{{{{(24k + 18)}^3}}} + \frac{2}{{{{(24k + 20)}^3}}} - \frac{6}{{{{(24k + 21)}^3}}} + \frac{1}{{{{(24k + 22)}^3}}}\\
\end{aligned} \right)\\
\end{aligned}$$
大括号可以嵌套,大括号之间可能有空格,但它们必须成对出现

我尝试了正则表达式
{*{((?>[^{}]+{{[^}]*})*}}*}
,但它不能匹配所有情况


如何改进我的正则表达式,或者这不能由正则表达式来完成,我必须编写一个简单的解析器?

正则表达式对于这项工作来说是错误的工具。正则表达式可以确定一种正则语言,但不能确定像这样的上下文无关语言(括号匹配是最常见的上下文无关语言之一)。总而言之,您需要编写一个基于堆栈的解析器(下推自动机)。

在JavaScript中使用正则表达式进行此操作非常麻烦。
首先,由于LaTeX是一种结构化文件格式,因此专门的解析器更合适。
漂亮的打印机插件(基于MichaelBrade的LaTeX.js)可能是解决您问题的灵丹妙药。(然而,JS中也有一些……但这是另一回事。)

其次,由于JS的正则表达式引擎不支持递归模式,事情变得更加困难。我们可以使用这样的模式(如果需要多次)来消除多余的大括号:

 \{[ ]*(\{(?:[^{}]+|(?1))*\})[ ]*\}
不幸的是,像递归第一个子模式的
(?1)
或递归整个模式的
(?R)
这样的语法不能在JS中使用。尽管如此,正如史蒂文·莱维坦(Steven Levithan)所证明的那样

尽管如此,考虑到已知的最大递归量 需要说明的是,这是很有可能的。这是解决办法 提供,与JavaScript配合使用效果很好(它不使用任何 高级正则表达式功能(实际上):

但是,这仅在以下情况下有效:

  • 支架总是平衡的,而且
  • […仅达到已知的最大递归级别]
让它适应手头的问题并不是特别困难,比方说两级递归

{[ ]*({(?:{(?:{.*?}|.)*?}|.)*?})[ ]*}
但有一个缺点:由于我们没有实际的递归模式,我们需要使用循环或帮助函数(如下面的演示代码)手动“递归”括号的
。替换

const str=`\$\$\\begin{aligned}
\\pi&=\\frac{1}{2}\\sum\\limits{k=0}^\\infty{\\frac{1}{{{16}^k}}}}}左({\\frac{8}{8k+2}+\\frac{4}{{8k+3}+\\frac{4}{8k+4}-\\frac{7})\\\\
\\5.2)及0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,,,,,,,,,,,{{{(6k+3)}^2}}-\\frac{6}{{{(6k+4)}^2}+\\frac{1}{{(6k+5)}^2}}\\右)\\\\
\\泽塔(3)&=\\frac{9}{{224}\\sum\\limits{k=0}^\\infty{\\frac{1}{{{{4096}^k}}}}
\\左(\\begin{aligned}
&\\frac{1024}{{(24k+2)}^3}}-\\frac{3072}{{(24k+3)}^3}+\\frac{{(24k+6)}{(24k+3)}{3}+\\frac{512}{{(24k+4)}^3}+\\frac{(24k+6)}{(24k+3)}{\\\\
+&{{{{{{384}{{{{{{{{{{{{{384}}{{{{{{{{{{{{{{{{{{{384}}}{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{383 3 3 3 3 3 3}}}}{{{{{{{{{{{{{{{{{}{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{72}{{{(24k+16)}^3}}\\\\
+&\\frac{{16}{{(24k+18)}^3}}+\\frac{2}{{(24k+20)}^3}}-\\frac{6}{{(24k+21)}^3}+\\frac{1}{(24k+22)}^3}}\\\\
\\结束{对齐}\\right)\\\\
\\结束{对齐}\$\$`;
常量subst=`1`;
常量正则表达式=/{[]*({(?:{.*.}|.*?}|.*?})[]*}/gm;
String.prototype.replacerec=函数(模式,什么){
var newstr=this.replace(模式,什么);
如果(newstr==此)
返回新闻TR;
return newstr.replace(模式、内容);
};
console.log(
str.replacerec(regex,subst)

);一种与嵌套级别无关的方法,它使用占位符

let latex=`$$\\begin{aligned}
\\pi&=\\frac{1}{2}\\sum\\limits{k=0}^\\infty{\\frac{1}{{{16}^k}}}}}左({\\frac{8}{8k+2}+\\frac{4}{{8k+3}+\\frac{4}{8k+4}-\\frac{7})\\\\
\\5.2)及0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,,,,,,,,,,,{{{(6k+3)}^2}}-\\frac{6}{{{(6k+4)}^2}+\\frac{1}{{(6k+5)}^2}}\\右)\\\\
\\泽塔(3)&=\\frac{9}{{224}\\sum\\limits{k=0}^\\infty{\\frac{1}{{{{4096}^k}}}}
\\左(\\begin{aligned}
&\\frac{1024}{{(24k+2)}^3}}-\\frac{3072}{{(24k+3)}^3}+\\frac{{(24k+6)}{(24k+3)}{3}+\\frac{512}{{(24k+4)}^3}+\\frac{(24k+6)}{(24k+3)}{\\\\
+&{{{{{{384}{{{{{{{{{{{{{384}}{{{{{{{{{{{{{{{{{{{384}}}{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{383 3 3 3 3 3 3}}}}{{{{{{{{{{{{{{{{{}{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{72}{{{(24k+16)}^3}}\\\\
+&\\frac{{16}{{(24k+18)}^3}}+\\frac{2}{{(24k+20)}^3}}-\\frac{6}{{(24k+21)}^3}+\\frac{1}{(24k+22)}^3}}\\\\
\\结束{对齐}\\right)\\\\
\\结束{对齐}$$`;
//我们保护字符串中的每一个最终文本波浪线
乳胶=乳胶。替换(/~/g,“~”);
//我们用
//钥匙。该键用于在映射中存储匹配的子字符串。
设substring=new Map(),
repNo=1;//使用要输入的假值初始化的替换数
//循环。
//替换模式检查子字符串是否不是包含的键
//在花括号之间:在这种情况下,括号将从键
//是已包含在花括号中的子字符串的占位符。
//重复此替换操作,直到无需替换为止。
对于(让级别=0;repNo>0;级别++){
repNo=0;
latex=latex.replace(/{((~l\d+n\d+~)|[^{}]*)}/g,(m,g1)=>{
{[ ]*({(?:{(?:{.*?}|.)*?}|.)*?})[ ]*}