我需要过滤一个(长)文本文件替换模式,可能是嵌套的。
不幸的是,模式有些模棱两可(以下不是完整列表):
\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ì.
)有点模棱两可,并且以下模式与“错误的”右括号匹配(“正确的”字符串应为:{{ 1}})。
我想分两步执行此操作,但要采用一些中间(明确)的形式,但这过于复杂,如果模式顺序颠倒(文件较长且存在多个嵌套条件),将无济于事。
注意:嵌套总是完整的;即;模式永远不会跨越彼此的边界,否则问题将无法解决。
进行此类替换的pythonic方法是什么?
答案 0 :(得分:2)
Pyparsing应该胜任这份工作。您可以使用Forward
为“一切”进行递归定义。
这是一个示例,其中包含一些调试信息以了解发生了什么情况
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ì.'], {})