首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >特定项之前的负正则表达式

特定项之前的负正则表达式
EN

Stack Overflow用户
提问于 2017-03-04 14:13:42
回答 2查看 89关注 0票数 6

我想解析一个LaTeX文档并用一个特殊的命令标记它的一些术语。具体来说,我有一份条款清单,例如:

代码语言:javascript
复制
Astah
UML
use case
...

我希望用以下自定义命令来标记文本中第一次出现Astah:\gloss{Astah}。到目前为止,这是可行的(使用Python):

代码语言:javascript
复制
for g in glossary:
    pattern = re.compile(r'(\b' + g + r'\b)', re.I | re.M)
    text = pattern.sub(start + r'\1' + end, text, 1)

而且效果很好。

但后来我发现:

  • I不希望匹配LaTeX内嵌注释后面的术语(因此,术语前面有一个或多个%)
  • 不希望在节标题中匹配术语(即\section{term}\paragraph{term})。

所以我试了一下:

代码语言:javascript
复制
for g in glossary:
    pattern = re.compile(r'(^[^%]*(?!section{))(\b' + g + r'\b)', re.I | re.M)
    text = pattern.sub(r'\1' + start + r'\2' + end, text, 1)

但它与前面有其他字符的注释中的术语相匹配,也与标题中的术语相匹配。

是因为我不明白雷克斯的“贪婪”吗?或者问题出在别的地方?

举个例子,如果我有这篇文章:

代码语言:javascript
复制
\section{Astah}
Astah is a UML diagramming tool... bla bla...
% use case:
A use case is a...

我想把它转化为:

代码语言:javascript
复制
\section{Astah}
\gloss{Astah} is a \gloss{UML} diagramming tool... bla bla...
% use case:
A \gloss{use case} is a...
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-04 14:33:09

这里的诀窍是使用在行开头开始匹配的正则表达式,因为这允许我们检查我们要匹配的单词是否前面有注释:

代码语言:javascript
复制
^([^%\n]*?)(?<!\\section{)(?<!\\paragraph{)\b(Astah)\b

需要多行标志m。此正则表达式的出现将被\1\\gloss{\2}所取代。

票数 1
EN

Stack Overflow用户

发布于 2017-03-04 18:22:26

这是我的两分钱:

首先,我们需要使用马修·巴尼特的正则模。它带来了许多有趣的特征。在本例中,它的一个特性可能很有用,即添加的(*SKIP)(*FAIL)

来自文档

  • 增加(*修剪)、(*跳过)和(*失败) (Hg问题153)

(*剪枝)在此之前丢弃回溯信息。当用于原子组或查找时,它不会影响包围模式。

(*SKIP)类似于(*PRUNE),但它也设置了文本中下一次匹配尝试将从何处开始。当用于原子组或查找时,它不会影响包围模式。

(*失败)导致立即回溯。(*F)是准许的缩写。

因此,让我们构建模式并使用regex模块对其进行测试:

代码语言:javascript
复制
import regex

pattern = regex.compile(r'%.*(*SKIP)(*FAIL)|\\section{.*}(*SKIP)(*FAIL)|(Astah|UML|use case)')

s = """
    \section{Astah}
    Astah is a UML diagramming tool... bla bla...
    % use case:
    A use case is a...
"""


print regex.sub(pattern, r'\\gloss{\1}', s)

产出:

节{Astah} \gloss{Astah}是一个\gloss{UML}图表工具。bla bla..。%用例:a\case{用例}是.

模式:

这句话很好地说明了这一点:

诀窍是匹配各种我们不想要的上下文,以便“中和它们”。

在左边,我们将写出我们不想要的上下文。在右边(最后一部分),我们捕捉到我们真正想要的东西。因此,所有的上下文都由一个交变符号|分开,最后一个上下文(我们想要的)被捕获。

因为在这种情况下,我们将执行替换,我们需要(*跳过)(*FAIL)来保持我们不想替换的匹配部件的完整性。

这个模式意味着什么:

代码语言:javascript
复制
%.*(*SKIP)(*FAIL)|\\section{.*}(*SKIP)(*FAIL)|(Astah|UML|use case)

%.*(*SKIP)(*FAIL)              # Matches the pattern but skip and fail
|                              # or
\\section{.*}(*SKIP)(*FAIL)    # Matches the pattern but skip and fail
|                              # or
(Astah|UML|use case)           # Matches the pattern and capture it. 

这个简单的技巧在RexEgg上更详细。

希望能帮上忙。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42596990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档