首页 > 解决方案 > 意外的 Ruby 正则表达式行为

问题描述

给定以下字符串,str

\begin{align*}
\intertext{Here is some text}
x^{2}+2x+3=2\\
\intertext{Here is some more}
\end{align*}

我想将 intertext 字符串移到 align 环境之外,如下所示:

Here is some text
\begin{align*}
x^{2}+2x+3=2\\
\end{align*}
Here is some more

请注意,我只想在互文出现在 \begin{something} 或 \end{something} 之前或之后立即执行此操作。考虑到这一点,我编写了以下正则表达式:

begin_align = /\\begin\{([^}]*)\}\n\\intertext\{([^}]*)\}/m
end_align = /\\intertext\{([^}]*)\}\n\\end\{([^}]*)\}/m

由于括号中的分组元素,当我调用 时m = str.match(begin_align),我可以抓取m[0](匹配的字符串)、m[1](在本例中应该是给定的环境align*)和m[2],它应该是 intertext 中的文本。如果我写str.match(m[0])我得到nil. 为什么?

我找到了解决这个问题的方法:如果我改为调用str.match(Regexp.quote(m[0])),我会得到匹配。但是,如果我随后尝试用 替换此匹配str.sub(Regexp.quote(m[0]),'')项,则没有任何反应。相反,如果我写str.sub(m[0],''),我会得到预期的结果。怎么来的?

当我试图调试这个例子时,我注意到了一些我无法理解的东西。如果我写 "\\begin{align".match("\\begin{align")
尽管它们是相同的字符串,但我找不到匹配项。如果我将第二个“逃脱”\\为:
"\\begin{align".match("\\\\begin{align")
那么我会得到一个匹配项。如果我然后尝试加上星号
"\\begin{align*".match("\\\\begin{align*")
我得到#<MatchData "\\begin{align">:它忽略了星号。我必须用 . 转义第二个星号\\*。这是怎么回事?

标签: rubyregexstring

解决方案


m[0]

\\begin{align*}\n\\intertext{Here is some text}

注意事项 .sub()

模式通常是Regexp; 如果作为 a 给出String,它包含的任何正则表达式元字符都将按字面意思解释。

所以m[0]contains *which 是一个量词。就它而言'*'.sub()它只是一个字面*字符。但由于.match()'*'被解释为量词和str.match('*')抛出错误的原因。align*在正则表达式上下文中,表示alig前面任意数量的n字符的字符串。

因此,.match()为了工作,您必须关心这些特殊字符,但使用并将其作为字符串传递.sub()只是一团糟。Regexp.quote


推荐阅读