代码之家  ›  专栏  ›  技术社区  ›  monotux

分析非统一但CSV格式的文本文件

  •  0
  • monotux  · 技术社区  · 12 年前

    我正在尝试分析以下文件(从本地银行导出的交易):

    Clnr   Kontonr     Konto                Valuta  Bokföringsdatum  Transaktionsdatum  Referens                            Kontohändelse                   Belopp
    12345  1234567890  vardagskonto         SEK     13-09-30         13-09-30           Hyresgästför                        Autogiro                        -15,00
    12345  1234567890  vardagskonto         SEK     13-09-30         13-09-30           SPOTIFY SPOTIFY                     Kortköp/uttag                   -19,00
    12345  1234567890  vardagskonto         SEK     13-09-30         13-09-30           +46123456789                        Swish mottagen                   80,00
    12345  1234567890  vardagskonto         SEK     13-09-30         13-09-30           PRIS NYCKELKUND                     Debiteringsavgift               -49,00
    12345  1234567890  vardagskonto         SEK     13-09-27         13-09-27           12345678                            direktbetalning                -301,00
    12345  1234567890  vardagskonto         SEK     13-09-27         13-09-27           Unionen                             Bg-bet. via internet           -125,00
    12345  1234567890  vardagskonto         SEK     13-09-26         13-09-26           123456789012345                     Överföring                   -1 000,00
    

    但我似乎无法为它创建一个合适的正则表达式。目标是提取第5、6、7和9列(当然,如果可以提取所有列,那将是一个额外的奖励),但第7列真的很棘手,因为文件不是CSV,第7列可以包含多个单词。第8列是不可预测的,但我认为我在上面的例子中发现了大多数相关的可能性。

    有关于如何成功解析此文件的提示吗?显然,我的正则表达式还不够。:-(

    如果有什么不同的话,我更希望它能用Python甚至POSIX(grep/sed/etc)来解决。

    3 回复  |  直到 12 年前
        1
  •  1
  •   georg    12 年前

    为了方便起见,以下是您可以“自动”解析这种格式的方法:

    import re
    
    # find out spaces' positions common to all rows
    spaces = sorted(set.intersection(*[
        set(m.end() for m in re.finditer(ur'\s', line))
        for line in data
    ]))
    
    # split by these positions
    for line in data:
        row = []
        p = 0
        for s in spaces:
            row.append(line[p:s])
            p = s
        row.append(line[p:])
        row = filter(len, map(unicode.strip, row))
        print ' | '.join(row) # or whatever you want...
    

    对于您的数据:

    data = u"""
    Clnr   Kontonr     Konto                Valuta  Bokföringsdatum  Transaktionsdatum  Referens                            Kontohändelse                   Belopp
    12345  1234567890  vardagskonto         SEK     13-09-30         13-09-30           Hyresgästför                        Autogiro                        -15,00
    12345  1234567890  vardagskonto         SEK     13-09-30         13-09-30           SPOTIFY SPOTIFY                     Kortköp/uttag                   -19,00
    12345  1234567890  vardagskonto         SEK     13-09-30         13-09-30           +46123456789                        Swish mottagen                   80,00
    12345  1234567890  vardagskonto         SEK     13-09-30         13-09-30           PRIS NYCKELKUND                     Debiteringsavgift               -49,00
    12345  1234567890  vardagskonto         SEK     13-09-27         13-09-27           12345678                            direktbetalning                -301,00
    12345  1234567890  vardagskonto         SEK     13-09-27         13-09-27           Unionen                             Bg-bet. via internet           -125,00
    12345  1234567890  vardagskonto         SEK     13-09-26         13-09-26           123456789012345                     Överföring                   -1 000,00
    """.strip().splitlines()
    

    这将打印:

    Clnr | Kontonr | Konto | Valuta | Bokföringsdatum | Transaktionsdatum | Referens | Kontohändelse | Belopp
    12345 | 1234567890 | vardagskonto | SEK | 13-09-30 | 13-09-30 | Hyresgästför | Autogiro | -15,00
    12345 | 1234567890 | vardagskonto | SEK | 13-09-30 | 13-09-30 | SPOTIFY SPOTIFY | Kortköp/uttag | -19,00
    12345 | 1234567890 | vardagskonto | SEK | 13-09-30 | 13-09-30 | +46123456789 | Swish mottagen | 80,00
    12345 | 1234567890 | vardagskonto | SEK | 13-09-30 | 13-09-30 | PRIS NYCKELKUND | Debiteringsavgift | -49,00
    12345 | 1234567890 | vardagskonto | SEK | 13-09-27 | 13-09-27 | 12345678 | direktbetalning | -301,00
    12345 | 1234567890 | vardagskonto | SEK | 13-09-27 | 13-09-27 | Unionen | Bg-bet. via internet | -125,00
    12345 | 1234567890 | vardagskonto | SEK | 13-09-26 | 13-09-26 | 123456789012345 | Överföring | -1 000,00
    
        2
  •  1
  •   Salem    12 年前

    您可以使用 re.split 以分离这些值。例子:

    import re
    
    raw_data = open("test.csv").readlines()
    header = raw_data[0]
    data = raw_data[1:]
    
    for line in data:
            values = re.split("\s{2,}", line.strip()) # splits by two or more spaces
            print list(values) # show as a list
    
        3
  •  -1
  •   Darka    12 年前

    为什么不使用此正则表达式:

    (.*?)(  +|\r\n|\n|$)
    

    似乎所有列都被2个空格隔开