如何在RegEx中寻址嵌套组?

2024-06-11 05:47:44 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有这样一段文字:

/TT0 1 Tf
0.002 Tc -0.002 Tw 11.04 0 0 11.04 221.16 707.04 Tm
[(\()-2(Y)7(o)7(u )-3(g)7(o)-2(t)4(i)-3(t)(\))]TJ
EMC 

它是PDF文件的一部分。线

^{pr2}$

包含文本“(你找到了)”。所以我首先需要匹配文本行

^[(.*)]TJ$

有了这个捕获组,我可以应用\(((.*?)\)[-0-9]*)并用\2替换所有匹配项。在

有可能一步到位吗?在


Tags: 文件文本pdftftmtwtc文字
2条回答

使用正则表达式解析嵌套组可能很困难、难以辨认或无法实现。在

寻址嵌套组的一种方法是使用parsing grammar。下面是一个使用Eric Rose的^{}库的3步示例。在

import itertools as it

import parsimonious as pars

# Given a source text*
source  = """\
/TT0 1 Tf
0.002 Tc -0.002 Tw 11.04 0 0 11.04 221.16 707.04 Tm
[(\()-2(Y)7(o)7(u )-3(g)7(o)-2(t )4(i)-3(t)(\))]TJ
EMC"""

# 1. Define a Grammar
rules = r"""

    root            = line line message end

    line            = ANY NEWLINE
    message         = _ TEXT (_ TEXT*)* NEWLINE
    end             = "EMC" NEWLINE*

    TEXT            = ~r"[a-zA-Z ]+" 
    NEWLINE         = ~r"\n"
    ANY             = ~r"[^\n\r]*"

    _               = meaninglessness*
    meaninglessness = ~r"(TJ)*[^a-zA-Z\n\r]*"    

"""

# 2. Parse source text and Build an AST
grammar = pars.grammar.Grammar(rules)
tree = grammar.parse(source)
# print(tree)

# 3. Resolve the AST
class Translator(pars.NodeVisitor):

    def visit_root(self, node, children):
        return children

    def visit_line(self, node, children):
        return node.text

    def visit_message(self, node, children):
        _, s, remaining, nl = children
        return (s + "".join(it.chain.from_iterable(i[1] for i in remaining)) + nl)

    def visit_end(self, node, children):
        return node.text

    def visit_meaninglessness(self, node, children):
        return children

    def visit__(self, node, children):
        return children[0]

    def visit_(self, node, children):
        return children

    def visit_TEXT(self, node, children):
        return node.text

    def visit_NEWLINE(self, node, children):
        return node.text

    def visit_ANY(self, node, children):
        return node.text

tr = Translator().visit(tree)
print("".join(tr))

输出

^{pr2}$

台阶

  1. 我们定义了一组类似regex/EBNF的语法规则see docs for details,而不是僵化的(有时难以辨认的正则表达式)。一旦定义了语法,如果需要,可以更容易地进行调整。
    • 注意:原始文本被修改,在2(t)(第3行)中添加了一个空格,因为它被认为是在操作中丢失的
  2. 解析步骤很简单。只要parse语法。如果语法被充分定义,那么AST会产生一组节点,反映源代码中已解析组件的结构。AST使这种方法更加灵活。在
  3. 定义访问每个节点时要执行的操作。可以使用任何所需的技术来解析AST。在这里,我们演示了NodeVisitor的子类化parsmonious,它实现了Visitor Pattern。在

现在,对于在pdf中遇到的新的或意外的文本,只需修改语法并再次解析即可。在

对于regex模块,您可以使用以下模式:

pat=r'(?:\G(?!\A)\)|\[(?=[^]]*]))[^](]*\(([^)\\]*(?:\\.[^)\\]*)*)(?:\)[^(]*]TJ)?'
regex.sub(pat, r'\1', s)

demo

图案细节:

^{pr2}$

相关问题 更多 >