python中的嵌套替换

2024-09-30 01:26:58 发布

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

我需要过滤一个(长)文本文件替换模式,可能是嵌套的。你知道吗

不幸的是,模式有点模棱两可(下面不是完整的列表):

  • \textit{whatever}->;@e{whatever}e@
  • \textbf{whatever}->;@b{whatever}b@
  • \tqt{whatever}->;@q{whatever}q@

嵌套模式时会出现问题,例如:

\tqt{Da oggi sarai conosciuto anche come \textbf{"guds morder"}: uccisore di Dei}, furono le ultime parole che sentì.

天真的实现:

import re
line = 'tqt{Da oggi sarai conosciuto anche come \textbf{"guds morder"}: uccisore di Dei}, furono le ultime parole che sentì.'
line = re.sub(r'\\textbf{([^}]+)}', r'@b{\1}b@', line)
line = re.sub(r'\\tqt{([^}]+)}', r'@q{\1}q@', line)

产生错误的答案(@q{Da oggi sarai conosciuto anche come @b{"guds morder"}q@b@: uccisore di Dei}, furono le ultime parole che sentì.),因为中间形式(\\tgt{Da oggi sarai conosciuto anche come @b{``guds morder''}b@: uccisore di Dei}, furono le ultime parole che sentì.)有点含糊不清,并且以下模式与“错误”的右大括号匹配(“正确”字符串应该是:@q{Da oggi sarai conosciuto anche come @b{"guds morder"}b@: uccisore di Dei}q@, furono le ultime parole che sentì.)。你知道吗

我想分两步来做,使用一些中间的(明确的)形式,但是这太复杂了,而且在模式顺序颠倒的情况下(文件很长并且存在几个嵌套条件)也没有帮助。你知道吗

注意:嵌套总是完整的;也就是说,模式永远不会跨越彼此的边界,否则问题就不会有解决方案。你知道吗

什么是Python的方式做这样的替代?你知道吗


Tags: le模式dawhateverdicomedeisarai
1条回答
网友
1楼 · 发布于 2024-09-30 01:26:58

Pyparsing应该适合这份工作。您可以使用Forward为“whatever”创建递归定义。你知道吗

下面是一个示例,通过一些调试打印来了解发生了什么:

import pyparsing as pp
pp.ParserElement.setDefaultWhitespaceChars('') #want to preserve whitespace as is

#a placeholder, to be filled in later
whatever = pp.Forward()

textit = "\\textit{" + whatever + "}"
def textit_action(inputs):
    print('textit')
    outputs = ["@e{"+''.join(inputs[1:-1])+"}e@"]
    return outputs
textit.setParseAction(textit_action)

textbf = "\\textbf{" + whatever + "}"
def textbf_action(inputs):
    print('textbf')
    outputs = ["@b{"+''.join(inputs[1:-1])+"}b@"]
    return outputs
textbf.setParseAction(textbf_action)

tqt = "\\tqt{" + whatever + "}"
def tqt_action(inputs):
    print('tqt')
    print(inputs)
    outputs = ["@q{"+''.join(inputs[1:-1])+"}q@"]
    return outputs
tqt.setParseAction(tqt_action)

anything = pp.Regex('[^\}\{]') 
#(there is probably a more pyparsing-y way to do this)
#Matching only a single character to make this not greedy.
#Else it matches e.g. 'test \textbf', swallowing the textbf.
#This is prevented now, as or_ takes the first that matches.
def anything_action(inputs):
    print('anything')
    print(inputs)
    return inputs
anything.setParseAction(anything_action)

other_brackets = '{' + whatever + '}'
def other_brackets_action(inputs):
    print('other brackets')
    print(inputs)
    return inputs
other_brackets.setParseAction(other_brackets_action)

or_ = pp.MatchFirst([textit, textbf, tqt, other_brackets, anything] )
whatever << pp.ZeroOrMore(or_)

def whatever_action(inputs):
    print('final')
    print(inputs)
    outputs = [''.join(inputs)]
    print(outputs)
    return outputs
whatever.setParseAction(whatever_action)

whatever.parseString(r'\tqt{Da oggi sarai conosciuto anche come \textbf{"guds morder"}: uccisore di Dei}, furono le ultime parole che sentì.')
(['@q{Da oggi sarai conosciuto anche come @b{"guds morder"}b@: uccisore di Dei}q@, furono le ultime parole che sentì.'], {})

相关问题 更多 >

    热门问题