从格式不一致的字符串中提取多个数据字段

2024-06-28 14:56:22 发布

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

无聊的背景故事:

My banking reports come in .pdf and .csv formats, but the older ones are only available to me as pdf's. I wanted to save the data in the same format as the newer ones to make it easier searchable, but the pdf's were protected, and after fiddling with unlockers and pdf-to-text converters, I ended up with terribly formatted files.

我有一个文件,其中每一行都是一个事务(比如:23.12 22.12.09 Verfügung Geldautomat\t63050000 / 9000481400\tGA NR00002317 BLZ63050000 0\t22.12/14.17UHR ESELSBERGW EUR 50,00\t-50,00

用数字替换数据字段会产生以下顺序和分隔符:

1 2 3\t7 / 6\t5\t4\t8

但我希望它是这种格式(原始数据中不存在的字段0、9和10是静态的)

"0";"1";"3";"4";"5";"6";"7";"8";"9";"10"

这是我当前的方法(没有I/O部分)

def readtrans(line):
    d1, d2, rest = line.split(' ', 2)
    d3, rest, d5, d4, d8 = rest.split('\t')
    d7, d6 = rest.split(' / ')
    return [d1, d2, d3, d4, d5, d6, d7, d8]

不幸的是,它在第一个文件的第3行崩溃,因为字段5和6对于字段3的某些值是空的。在添加了一个if子句来解决这个问题之后,脚本前进到第5行只是为了再次崩溃,因为字段4可能还包含制表符。我也可以解决这个问题,但我把它当作一个提示,去寻找一个更灵活的解决方案。在

大多数时候,当我需要从文本中提取数据时,我会相应地查看分隔符和split()。它可能不是很有效,但它比查找正则表达式语法要快,我很少使用它,而且经常忘记它。在这种情况下,这是一种可行的方法,还是regex更适合?regex甚至可以处理这个任务吗?如果是的话,它仍然是可读的吗?你会怎么解决?在

编辑: 确实,我再也不会使用这段代码了,(顺便说一下,这是我的解决方案),但这是一个非常常见的问题

^{pr2}$

在思考了如何重新表述我的问题之后,我意识到它基本上是这个问题的重复

有了新的知识,我编造了这个简短的模式,可以正确地解析我的示例

import re
example = '23.12 22.12.09 Verfügung Geldautomat\t63050000 / 9000481400\tGA NR00002317 BLZ63050000 0\t22.12/14.17UHR ESELSBERGW EUR 50,00\t-50,00'
x = re.search(r'(\S+) (\S+) ([\S| ]+)\t(\S+) / (\S+)\t([\S| ]+)\t([\S| ]+)\t([\S| ]+)', example)
print x.groups()
>>>('23.12',
'22.12.09',
'Verf\xc3\xbcgung Geldautomat',
'63050000',
'9000481400',
'GA NR00002317 BLZ63050000 0',
'22.12/14.17UHR ESELSBERGW EUR 50,00',
'-50,00')

钥匙是用的重组()


Tags: andthetoinrestpdfeurbut
2条回答

我要做几个假设: 1) 你可能再也不会使用这个代码了 2) 只有几种可能的格式

我不会费心为这个制定一个RE,因为它不需要如此强大。(见假设1)。在

我可能会设法找出一些方法来确定我正在阅读的特定行使用的格式。然后使用一些if语句,通过适当的定界步骤将其发送到,以获得所需的字段顺序。(见假设2)。在

我很快就想出了一个例子,你显然需要做很多改变才能使它适合你的情况,但是你明白了。最困难的部分可能是找出一种方法来决定使用哪个解码器…我在我的例子中使用了“标签的位置”。在

def decoder1(line):
    parts = line.split("\t")
    d1, d2 = parts[0].split(",")
    d3, d4, d5, d6, d7, d8, d9 = parts[1].split(",")
    return [d1, d2, d3, d4, d5, d6, d7, d8, d9]


def decoder2(line):
    parts = line.split("\t")
    d1 = parts[0]
    d2, d3, d4, d5, d6, d7, d8, d9 = parts[1].split(",")
    return [d1, d2, d3, d4, d5, d6, d7, d8, d9]


def decoder3(line):
    parts = line.split("\t")
    d1, d2, d3, d4, d5, d6, d7 = parts[0].split(",")
    d8, d9 = parts[1].split(",")

    return [d1, d2, d3, d4, d5, d6, d7, d8, d9]


if __name__ =="__main__":
    lines = [
            "1,2\t3,4,5,6,7,8,9",
            "1\t2,3,4,5,6,7,8,9",
            "1,2,3,4,5,6,7\t8,9"
            ]

    for line in lines:
        tablocation = len((line.split("\t")[0]).split(","))
        if tablocation == 2:
            res = decoder1(line)
        elif tablocation == 1:
            res = decoder2(line)
        elif tablocation == 7:
            res = decoder3(line)
        else:
            print "Must be a new format for %s" %line
            res = "NA"
        print res

如果你有更多的“解码器选项”,那么花时间开发一些REs可能是值得的,但是如果你不知道所有可能的变化,很难提供比我在上面的方法中展示的更多的帮助。在

在你的问题中有点混乱,但我认为你在问的是:

How do I specify multiple delimiters to split on, some of which may be more than one character long?

答案是使用re.split()

s = '1 2 3\t7 / 6\t5\t4\t8'

import re

re.split(r'\s/\s|\s|\t',s)
Out[13]: ['1', '2', '3', '7', '6', '5', '4', '8']

你可以在你认为合适的时候重新排列你的最终输出。在

注意:通常在这些多分隔符问题中,您可以任意指定要拆分的标记的顺序。这里不是这样。在

^{pr2}$

您需要在之前查找\s/\s,因为后者是前者的子串。在

相关问题 更多 >