簡體   English   中英

從格式不統一的字符串中提取多個數據字段

[英]Extract multiple data fields from a non-uniformly formatted string

無聊的背景故事:

我的銀行報告以.pdf和.csv格式提供,但較舊的報告僅以pdf格式提供給我。 我想以與較新的格式相同的格式保存數據,以使其更易於搜索,但是pdf受到了保護,並且在對解鎖程序和pdf到文本轉換器進行擺弄后,最終得到了格式非常糟糕的文件。

我有每行交易的文件(例如: 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-clause來解決此問題之后,腳本前進到了第5行,只是再次崩潰了,因為字段4可能還包含標簽。 我也可以解決這個問題,但是我以此為線索尋求更靈活的解決方案。

大多數時候,當我需要從文本中提取數據時,我會看一下分隔符並相應地split() 它可能不是很有效,但是比查找我很少使用並反復忘記的正則表達式語法快。 在這種情況下這是可行的方法,還是正則表達式更合適? 正則表達式甚至可以處理此任務,如果可以,它仍然可讀嗎? 您將如何解決?

編輯:是的,我再也不會使用此代碼了(順便說一下,這是我的解決方案),但這是一個非常常見的問題

def readtrans(line):
    d1, d2, rest = line.split(' ', 2)
    if rest[0] == 'A':
        d3, d7, d4, d8 = rest.split('\t')
        d5 = ''
        d6 = ''
    else:  
        d3, d7d6, d5, d4d8 = rest.split('\t', 3)
        d7, d6 = d7d6.split(' / ')
        rest = d4d8.split('\t')
        d8 = rest[-1]
        d4 = ' '.join(rest[:-1])
    return [d1, d2, d3, d4, d5, d6, d7, d8]

在考慮了如何改寫我的問題之后,我意識到這基本上是這個字符串轉換為變量的副本(例如format(),但相反)

有了新知識,我制作了這個簡短的模式來正確解析我的示例

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')

關鍵是使用re.groups()

我將作一些假設:1)您可能永遠不會再使用此代碼2)只有幾種可能的格式

我不會為此而煩惱,因為它不需要那么強大。 (請參閱假設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

如果您擁有多個“解碼器選項”,那么值得花一些時間來開發一些RE。 但是,如果不知道您可能擁有的所有變體,將很難提供比我上面的方法所示更多的幫助。

您的問題中有些雜音,但這是我您要問的問題:

如何指定多個分隔符來分割,其中一些可能超過一個字符長?

答案是使用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']

您可以根據需要將訂單重新排列到最終輸出中。

注意:通常在這些多定界符問題中,您可以任意指定要分割的標記的順序。 這里不是。

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

您需要先查找\\s/\\s 然后才查找\\s ,因為后者是前者的子字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM