使用“魔法”值解析文本文件

时间:2018-01-31 18:35:01

标签: python regex python-2.7 parsing python-2.x

背景

我在自动化脚本中使用了一些大型文本文件来进行音频调整。文本文件中的每一行看起来大致如下:

A[BANANA] + B[PINEAPPLE] - C[CHERRY] [[BANANA]] BANANA # BANANA

文本被送到一个旧的命令行程序,该程序搜索关键字并将它们交换出来。样本输出将是:

A[0] + B[100] - C[0x1000] [[0]] 0 # 0
A[2] + B[200] - C[0x100A] [[2]] 0 # 0

问题

有时,文本文件中的关键字应保持不变(即我们不希望“BANANA”替换的情况)。我想修改文本文件以使用某种在正常情况下不太可能弹出的关键字/分隔符,即:

A[#1] + B[#2] - C[#3] [[#1]] #1 # #1

问题

python的文本文件解析器是否有我可以使用的特殊索引/转义序列而不是简单的关键字?

5 个答案:

答案 0 :(得分:2)

您可以使用re.sub执行替换。这个答案会创建一个随机值列表来演示,但是,列表可以替换为您正在使用的数据:

import re
import random
s = "A[BANANA] + B[PINEAPPLE] - C[CHERRY] [[BANANA]]"
new_s = re.sub('(?<=\[)[a-zA-Z0-9]+(?=\])', '{}', s)
random_data = [[random.randint(1, 2000) for i in range(4)] for _ in range(10)]
final_results = [new_s.format(*i) for i in random_data]
for command in final_results:
  print(command)

输出:

A[51] + B[134] - C[864] [[1344]]
A[468] + B[1761] - C[1132] [[1927]]
A[1236] + B[34] - C[494] [[1009]]
A[1330] + B[1002] - C[1751] [[1813]]
A[936] + B[567] - C[393] [[560]]
A[1926] + B[936] - C[906] [[1596]]
A[1532] + B[1881] - C[871] [[1766]]
A[506] + B[1505] - C[1096] [[491]]
A[290] + B[1841] - C[664] [[38]]
A[1552] + B[501] - C[500] [[373]]

答案 1 :(得分:2)

使用正则表达式替换函数和字典。

匹配括号之间的所有内容(非贪婪,避免使用括号本身)并替换为dict的值,如果找不到原始值,则放置原始值:

import re

d = {"BANANA":"12", "PINEAPPLE":"20","CHERRY":"100","BANANA":"400"}
s = "A[BANANA] + B[PINEAPPLE] - C[CHERRY] [[BANANA]]"

print(re.sub("\[([^\[\]]*)\]",lambda m : "[{}]".format(d.get(m.group(1),m.group(1))),s))

打印:

A[400] + B[20] - C[100] [[400]]

答案 2 :(得分:1)

只需使用

\[([^][]+)\]

并将其替换为所需的结果,例如: 123

<小时/> 分解,这说

\[       # opening bracket
([^][]+) # capture anything not brackets, 1+ times
\]       # closing bracket

a demo on regex101.com

<小时/> 对于您更改的要求,您可以使用OrderedDict

import re
from collections import OrderedDict

rx = re.compile(r'\[([^][]+)\]')
d = OrderedDict()

def replacer(match):
    item = match.group(1)
    d[item] = 1
    return '[#{}]'.format(list(d.keys()).index(item) + 1)

string = "A[BANANA] + B[PINEAPPLE] - C[CHERRY] [[BANANA]]"
string = rx.sub(replacer, string)
print(string)

哪个收益

A[#1] + B[#2] - C[#3] [[#1]]

这里的想法是将每个(可能的)新项目放入dict中,然后搜索索引。 OrderedDict记住订单输入。

<小时/> 为了学术完整性,您也可以自己完成所有工作:

import re

class Replacer:
    rx = re.compile(r'\[([^][]+)\]')
    keywords = []

    def do_replace(self, match):
        idx = self.lookup(match.group(1))
        return '[#{}]'.format(idx + 1)

    def replace(self, string):
        return self.rx.sub(self.do_replace, string)

    def lookup(self, item):
        for idx, key in enumerate(self.keywords):
            if key == item:
                return idx

        self.keywords.append(item)
        return len(self.keywords)-1

string = "A[BANANA] + B[PINEAPPLE] - C[CHERRY] [[BANANA]]"

rpl = Replacer()
string = rpl.replace(string)
print(string)

答案 3 :(得分:1)

也可以使用pyparsing完成。

这个解析器实质上将noun定义为方括号内的大写字母,然后将它们的序列定义为一行输入,如complete

要使用其他内容替换标识的项目,请以合适的方式定义class dict,以便class以外的任何内容保持不变。

>>> import pyparsing as pp
>>> noun = pp.Word(pp.alphas.upper())
>>> between = pp.CharsNotIn('[]')
>>> leftbrackets = pp.OneOrMore('[')
>>> rightbrackets = pp.OneOrMore(']')
>>> stmt = 'A[BANANA] + B[PINEAPPLE] - C[CHERRY] [[BANANA]]'
>>> one = between + leftbrackets + noun + rightbrackets
>>> complete = pp.OneOrMore(one)
>>> complete.parseString(stmt)
(['A', '[', 'BANANA', ']', ' + B', '[', 'PINEAPPLE', ']', ' - C', '[', 'CHERRY', ']', ' ', '[', '[', 'BANANA', ']', ']'], {})
>>> class Replace(dict):
...     def __missing__(self, key):
...         return key
...     
>>> replace = Replace({'BANANA': '1', 'PINEAPPLE': '2'})
>>> new = []
>>> for item in complete.parseString(stmt).asList():
...     new.append(replace[item])
... 
>>> ''.join(new)
'A[1] + B[2] - C[CHERRY] [[1]]'

答案 4 :(得分:1)

我认为使用plex更容易 - 也更清晰。问题在于它似乎仅适用于Py2。我花了一两个小时才把足够的转换工作交给Py3来实现。

只需要注意三种类型的令牌,然后在while语句中使用相同数量的分支。

from plex import *
from io import StringIO

stmt = StringIO('A[BANANA] + B[PINEAPPLE] - C[CHERRY] [[BANANA]]')

lexicon = Lexicon([
    (Rep1(AnyBut('[]')), 'not_brackets'),
    (Str('['), 'left_bracket'),
    (Str(']'), 'right_bracket'),
])

class Replace(dict):
    def __missing__(self, key):
        return key

replace = Replace({'BANANA': '1', 'PINEAPPLE': '2'})

scanner = Scanner(lexicon, stmt)
new_statement = []
while True:
    token = scanner.read()
    if token[0] is None:
        break
    elif token[0]=='no_brackets':
        new_statement.append(replace[token[1]])
    else:
        new_statement.append(token[1])

print (''.join(new_statement))

结果:

A[BANANA] + B[PINEAPPLE] - C[CHERRY] [[BANANA]]