【问题标题】:Context-aware regular expression上下文感知正则表达式
【发布时间】:2017-03-20 15:36:49
【问题描述】:

我有一个很长的 Latex 文档,并被要求将数学符号大写 A 的每个外观更改为小写 a。

唯一的问题是这个符号在乳胶数学表达式中重复了很多次(我猜超过 300 次)。它还在一个表达式中出现多次。

我想手动修复这个需要付出相当大的努力,更不用说我肯定会忽略许多替换。另外,请注意标准编辑器的正常“查找/替换”功能在这里是没有问题的,因为字母 A(不是数学符号 A)几乎出现在文档中的任何地方。

所以我认为正则表达式是解决我问题的好选择;但是,我需要确保我做对了,这就是这篇文章的主要原因。如果有人可以查看下面的正则表达式并告诉我可能出现的问题以及如何解决它,我将不胜感激。

首先,我需要列出我想用 grep 修复的地方,所以我写道:

$ # list all the occurrences of "A" inside latex math environment
$ # i.e., surrounded by $ $ 
$ # Note that since $ is a special char in regex, we have to escape it
$ grep -n '\$[^\$]*A[^\$]*\$' doc.tex

这个 grep 按预期工作,但不是我想要的。为了说明这个问题,请考虑以下简单示例:

$ cat -n test.tex 
     1  Abc $y_1=A x$. 
     2  Abc $y_2=b x$. Abc $c^2$.
     3  Abc $y_2=b x$.
     4  Abc $y_1=A x$. 
     5  abc $y_1=x$.
     6  abc abc. $E=mc^2$.
$ grep -n '\$[^\$]*A[^\$]*\$' test.tex 
1:Abc $y_1=A x$. 
2:Abc $y_2=b x$. Abc $c^2$.
4:Abc $y_1=A x$.

第 2 行由 grep 显示,但我不希望出现这种情况,因为匹配的 A 在数学环境分隔符之外。是否可以修复这个正则表达式,以避免类似于第二个匹配的情况?我想我的问题可以概括为询问正则表达式是否可以了解其上下文?

如果我想解决我的问题,我会建议以下“抽象想法”:

 B = TRUE 
 For every match that grep finds
     If B is TRUE 
        Display the match
     End if
     B = not B
 End for

换句话说,当 grep 找到匹配项时,仅当 B 为 TRUE 时才显示它,反转 B,并对所有匹配项重复。

这个想法应该可行,因为我的文档中没有嵌套的数学表达式。那么我们可以用 grep 来实现这个想法吗?或者有什么更好的主意吗?

【问题讨论】:

  • 第 2 行的第二部分,$. Abc $c^2$$..$ 之间存在A,如何避免这种情况(条件)?
  • 您可以使用单词边界来限制独立的字母匹配,但仍然需要担心跨越多行的数学环境,或文本中美元符号的其他用途。
  • 您可以考虑将原始的A 替换为适当的命令,这样以后如果您需要将小写的as 再次更改为其他内容,您只需更改命令的定义在一处。
  • 嗨@Inian:我在帖子中写的“抽象”想法怎么样?你不认为它可以解决我的问题,或者至少在概念上吗?你不觉得这是可以实现的吗?
  • 嗨@karakfa:真实有效的cmets,谢谢。

标签: regex bash grep


【解决方案1】:

我会尝试:

perl -pnE 's/ (\$.*?\$) / $1 =~ s:A:a:gr /xge'
  • 它搜索 pairsdollar text dollar(例如数学表达式)
  • 在每对内部更改 A -> a
  • 重复下一对
  • 这些对在下面显示为mmmmm

例如来自

Abc $y_2=A A x$. A A $c^2$. Ab A $y_1=AaA x$. A $ dol
____mmmmmmmmmmm______mmmmm_______mmmmmmmmmmm_________ 
# the  m shows the matched pairs e.g. the "inside of the math expr"

生产

Abc $y_2=a a x$. A A $c^2$. Ab A $y_1=aaa x$. A $ dol

EDIT2 - 用于多行和荣誉转义\$

允许多行需要有点不同:

perl -0 -pE 's/ (\$.*?\$) / $1 =~ s:A:a:gr /xges' file.lat
perl -0 -pE 's/ (?<!\\) (\$ .*? (?<!\\) \$) / $1 =~ s:A:a:gr /xges'
  • -0“啜饮”整个文件到 perl 中
  • 并添加了s 修饰符
  • \$ 使用否定的lookbehind

来自输入的演示

Abc $y_1=A x$. 
Abc $y_2=b x$. Abc $c^2$. $y_1=A x$.
Abc $y_2=b x$.
Abc $y_1=A x
      still AAA inside multi line
      math AAA end->$. A-outside here
 in \$ still in AAA out \$ still out.
still A outside $ Again A AA inside
multi  up to \$ still AA inside
here $ A out
abc $y_1=x$.
abc abc. $E=mc^2$.

生产

Abc $y_1=a x$. 
Abc $y_2=b x$. Abc $c^2$. $y_1=a x$.
Abc $y_2=b x$.
Abc $y_1=a x
      still aaa inside multi line
      math aaa end->$. A-outside here
 in \$ still in AAA out \$ still out.
still A outside $ again a aa inside
multi  up to \$ still aa inside
here $ A out
abc $y_1=x$.
abc abc. $E=mc^2$.

Ps:对不起,我有限的英语无法提供更详细的解释......

【讨论】:

  • 嗨@jm666:可以解释一下答案中的代码吗?很抱歉问你这个问题,但我不熟悉 perl 语言的语法。
  • 谢谢@jm666。你解释得很清楚。请再问一个问题:如何跨多行匹配一对 $?
  • 没有提示...perl 是一个勤奋的人,不会喋喋不休... :)
  • 可能的问题:\$ 被视为$$$ 数学模式无法识别。
  • \$ 应该被忽略/视为普通字符。在您的示例中,DAF 在外面。另一个例子:$ in \$ still in $ out \$ still out.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 2011-10-03
  • 1970-01-01
相关资源
最近更新 更多