特定术语前的负面正则表达式

时间:2017-03-04 14:13:42

标签: python regex latex

我想解析一个LaTeX文档并用特殊命令标记它的一些术语。具体来说,我有一个术语列表,比如说:

Astah
UML
use case
...

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

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)

它工作正常。

但后来我发现了:

  • 不希望匹配LaTeX内联评论后的字词(因此术语前面有一个或多个%
  • 并且我不希望匹配部分标题内的字词(即\section{term}\paragraph{term}

所以我尝试了这个:

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)

但它匹配注释中的术语,前面跟着其他字符,它也匹配标题内的术语。

我不理解正则表达式的“贪婪”吗?或者问题可能在其他地方?

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

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

我想将其转换为:

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

2 个答案:

答案 0 :(得分:1)

这里的诀窍是使用在行首开始匹配的正则表达式,因为这样我们就可以检查我们尝试匹配的单词是否有注释:

m

需要多行标记\1\\gloss{\2}。这个正则表达式的出现将被替换为 let predicate = NSPredicate(format: "timeStamp == %@", parcoursTimeStamp as CVarArg) let query = CKQuery(recordType: "ParcoursRecord", predicate: predicate) privateDatabase.perform(query, inZoneWith: recordZone.zoneID, completionHandler: { (result, error) in if let error = error { print("Error querying for record: \(error.localizedDescription)") } else { print("Query result: \(result)") } })

答案 1 :(得分:0)

这是我的两分钱:

首先,我们需要使用regex module by Matthew Barnett。它带来了许多有趣的功能。在这种情况下,其功能之一可能很有用,添加了(*SKIP)(*FAIL)

来自documentation

  
      
  • 新增(* PRUNE),(*跳过)和(*失败)(Hg issue 153)
  •   
     

(* PRUNE)会丢弃回溯信息。用于   原子组或环视,它不会影响封闭   图案。

     

(* SKIP)类似于(* PRUNE),除了它还设置在哪里   文本下一次匹配尝试将开始。在原子中使用时   组或环视,它不会影响封闭模式。

     

(* FAIL)导致立即回溯。 (* F)是允许的   缩写

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

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)

输出:

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

模式:

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

  

诀窍是匹配我们不想要的各种情境,以便中和它们"。

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

因为在这种情况下,我们将进行更换,我们需要(* SKIP)(* FAIL)保持我们不想替换的匹配部分。

模式的含义:

%.*(*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上更详细。

希望它有所帮助。