匹配其他标签的正则表达式(字符串对)

regex to match othermost tags (string pair)

我有一本书是用 Sweave 写的,其中包含很多我正在尝试转换为 Rmarkdown 的 Latex。我设法编写了一个脚本,将大部分 Latex 转换为合理的降价,但嵌套列表让我望而却步。

到目前为止,我的想法是检测列表何时开始和结束,然后将其传递给 pandoc 进行转换,因为我认为制作解析器会使它变得不必要的困难。 问题是在嵌套列表时检测列表的开始和结束位置。

我在这里找到了一个匹配方括号标签的例子,但我一直无法弄清楚如何将它转换为匹配 \begin 和 \end。 ()

示例数据:

meh meh

\begin{itemize}
\item something1
\begin{itemize}
\item something1.1
\item something1.2
\end{itemize}
\item something2
\begin{itemize}
\item something2.1

\item something2.2
\end{itemize}
\end{itemize}

blah blah

\begin{itemize}
\item somethingelse1
\item somethingelse2
\end{itemize}

the end.

上面应该有两场比赛。一个用于嵌套列表,一个用于下面的列表。 这可以用正则表达式来完成吗?还是您看到了一些更聪明的方法?

\begin{...}\end{...}之间递归匹配的正则表达式是PCRE正则表达式,如

(?s)\begin\{[^{}]*}(?:(?!\(?:end|begin)).|(?R))*\end\{[^{}]*}

一个更高效的正则表达式版本(展开后,我还在前瞻中的 \begin\end 之后添加了对 { 的检查)是:

\begin\{[^{}]*}(?:[^\]*(?:\(?!(?:end|begin)\{)[^\]*)*|(?R))*\end\{[^{}]*}

参见regex demo #1 and regex demo #2详情:

  • (?s) - singleline/dotall/s 修饰符使 . 跨行匹配
  • \begin\{ - \begin{ 字符串
  • [^{}]* - {}
  • 以外的零个或多个字符
  • } - 一个 } 字符
  • (?:(?!\(?:end|begin)).|(?R))* - 尽可能多地出现零次或多次
    • (?!\(?:end|begin)). - 任何不以 \end\begin 字符序列开头的字符
    • | - 或
    • (?R) - 整个正则表达式模式是递归的
  • \end\{ - \end{ 字符串
  • [^{}]*} - {} 以外的零个或多个字符,然后是 } 个字符。

示例 R 代码:

x <- "meh meh\n\begin{itemize}\n\item something1\n\begin{itemize}\n\item something1.1\n\item something1.2\n\end{itemize}\n\item something2\n\begin{itemize}\n\item something2.1\n\item something2.2\n\end{itemize}\n\end{itemize}\nblah blah\n\begin{itemize}\n\item somethingelse1\n\item somethingelse2\n\end{itemize}\nthe end.\n"
reg <- "(?s)\\begin\{[^{}]*}(?:(?!\\(?:end|begin)).|(?R))*\\end\{[^{}]*}"
## reg2 <- "\\begin\{[^{}]*}(?:[^\\]*(?:\\(?!(?:end|begin)\{)[^\\]*)*|(?R))*\\end\{[^{}]*}"
result <- regmatches(x, gregexpr(reg, x, perl=TRUE))

输出:

> result
[[1]]
[1] "\begin{itemize}\n\item something1\n\begin{itemize}\n\item something1.1\n\item something1.2\n\end{itemize}\n\item something2\n\begin{itemize}\n\item something2.1\n\item something2.2\n\end{itemize}\n\end{itemize}"
[2] "\begin{itemize}\n\item somethingelse1\n\item somethingelse2\n\end{itemize}"