python - 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ì.
。
我曾想过分两步执行此操作,使用一些中间(明确)形式,但这过于复杂,并且在模式顺序颠倒的情况下无济于事(文件很长并且存在多个嵌套条件)。
注意:嵌套总是完整的;IE; 模式永远不会跨越彼此的界限,否则问题将无法解决。
进行此类替换的pythonic方法是什么?
解决方案
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ì.'], {})
推荐阅读
- android - 如何使用 android studio 项目中提供的默认启动器图标作为 ImageView(原样)?
- ios - 有条件的,如果为目标 c 进口
- angular - Angular:测试 Http POST 方法
- sql - 将选择结果传递给 SQL 中的 like 运算符
- spring-boot - 如果基本身份验证请求即将到来,如何跳过 jwt 令牌身份验证?
- c++ - 澄清琐碎的析构函数
- react-native - React-Native AsyncStorage:我检索了一个数组,但后来它变成了数组的一个对象
- java - 在 spring boot 和 jersey 之间使用服务器发送事件时锁定线程
- python - 在opencv python中同步两个视频
- python - python - 如何避免重复数据馈送到python中的sqlite数据库?