用Python解析半未结构的文本文件.保留一些行并使其他行动旋转



我有一个具有不错的结构的文件,但是后续事件的日期(一个或多个(仅打印一次。我无法弄清楚如何读取文件,识别日期以及将其映射到随后的每个游戏结果之前,直到下一个日期出现为止。

数据看起来像这样:

Sa 19.11.2016 
FC Tuggen
FC Basel 1893 II 
1
3
SC Cham 
FC Zürich II 
0
1
SC Kriens
FC Köniz  
3
1
Sa 26.11.2016 
FC Bavois
SC Brühl  
1
4
Mi 30.11.2016 
FC Zürich II
FC Basel 1893 II 
2
2

每个日期可以应用于一个或多个游戏结果。我已经尝试阅读文件和grepping日期

keys = []
for line in d:
    if line[0:2] in ('Sa','So','Mo','Di','Mi','Do','Fr'):
        keys.append(line[2:-1].strip())

,但是我不知道如何将同一日期分配给下一个游戏,直到下一个日期到达。为此,我尝试了枚举((,xrange((等各种组合。

我所需的输出外观如下,或以键为小词典的日期和数组元素的默认值(列表(:

Sa 19.11.2016,FC Tuggen,FC Basel 1893 II,1,3
Sa 19.11.2016,SC Cham,FC Zürich II,0,1
Sa 19.11.2016,SC Kriens,FC Köniz,3,1
Sa 26.11.2016,FC Bavois,SC Brühl,1,4
Mi 30.11.2016,FC Zürich II,FC Basel 1893 II,2,2

的某些内容就像以下内容一样可行,假设输入文件的格式类似于您所显示的格式。使用变量跟踪最后一个观看日期。

lastseendate = None
gameinfo = []
for line in f:
    if line[0:2] in ('Sa','So','Mo','Di','Mi','Do','Fr'):  # date row
        lastseendate = line.strip()
    elif len(line.strip()) == 0:  # empty line
        print(lastseendate + ',' + ','.join(gameinfo))  # print out the row for game just read before
        gameinfo = []  # ready to read the next game info
    else:
        gameinfo.append(line.strip())

如果日期之前的两个字符太多而无法进行硬码,则可以使用以下正则表达式。

import re
pat = re.compile("[A-Za-z] d{2}.d{2}.d{4}")

然后用

替换# date row
if pat.match(line):

编辑

  1. 除非文件末尾有一个空行,否则该代码不会打印文件中最后一个游戏的信息。要解决此问题,请在文件末尾添加一个空行,或在循环结束后重复打印语句。
  2. 在打印语句中删除了n(不必要,因为print已经打印了新行(。
# vim: set fileencoding=utf-8 :

def parse(it):
  record, date = [], ""
  for line in it:
    line = line.strip()
    if not line:
      if len(record) > 1:
        yield ",".join(record)
      if date:
        record = [date]
      continue
    if line.startswith(('Sa', 'So', 'Mo', 'Di', 'Mi', 'Do', 'Fr')):
      if len(record) > 1:
        yield ",".join(record)
      date = line
      record = [date]
      continue
    record.append(line)
  if len(record) > 1:
    yield ",".join(record)

if __name__ == "__main__":
  input = """
Sa 19.11.2016
FC Tuggen
FC Basel 1893 II
1
3
SC Cham
FC Zürich II
0
1
SC Kriens
FC Köniz
3
1
Sa 26.11.2016
FC Bavois
SC Brühl
1
4
Mi 30.11.2016
FC Zürich II
FC Basel 1893 II
2
2
"""
  output = """Sa 19.11.2016,FC Tuggen,FC Basel 1893 II,1,3
Sa 19.11.2016,SC Cham,FC Zürich II,0,1
Sa 19.11.2016,SC Kriens,FC Köniz,3,1
Sa 26.11.2016,FC Bavois,SC Brühl,1,4
Mi 30.11.2016,FC Zürich II,FC Basel 1893 II,2,2
"""
  for record, expected in zip(parse(input.splitlines()), output.splitlines()):
    assert record == expected

编辑:好的,早些时>

首先,我逐行划分文本。通过每行,我做了几件事。第一,我跟踪起始线路,这是空线后的第一行和任何线路。一个空线还将需求标志设置为true。

对于不是空的行,我使用正则搜索日期。如果我找到一个,则将其设置为(当前(日期。否则,我检查是否设置了需求(由于上一行为空(,如果是这样,则将日期附加到该行。

然后我对行进行了分组,每个启动线使用我的sublist函数启动组,然后我将分组的线条与逗号一起加入。

tf = """Sa 19.11.2016
FC Tuggen
FC Basel 1893 II
1
3
"""
import re
i=0
sl=[0] #start lines
gnu = True
dlt = False # date last turn
lines = tf.split('n')
for line in lines:
    line = line.rstrip()
    if not line == '':
        regex = re.search('[A-Za-z]+ [0-9]+.[0-9]+.[0-9]+', line)
        if regex:
            date = regex.group(0) 
            dlt = True
        elif needDate:
            lines[i] = date + ',' + line
        needDate= False
    else:
            sl.append(i+1)
            needDate = True
    i += 1
def subList(lzt, inds):
    tups = []
    for i in range(len(inds)):
        if i < len(inds)-1:
            tups.append( (inds[i], inds[i+1]))
        else:
            tups.append( (inds[i], len(lzt)))
    return [lzt[s:e] for s,e in tups]
ans = []
for x in subList(lines, sl):
    ans.append(",".join(x[:-1]))
for line in ans:
    print(line)

此替代应对,无论末尾是否有空白。重要的想法是发送代表文件终止的其他令牌,这可能是多余的。

class Token:
    def __call__ (self, token):
        if len(token) == 0 or token=='-':
            print (','. join(self.content))
        if token[0:2] in ('Sa','So','Mo','Di','Mi','Do','Fr'):
            self.content = [token]
        else:
            self.content.append(token)
token = Token()
with open('football.txt') as football:
    for line in football.readlines():
        token(line.strip())
    line = football.readline()
    token('-')

结果:

Sa 19.11.2016,FC Tuggen,FC Basel 1893 II,1,3
Sa 19.11.2016,FC Tuggen,FC Basel 1893 II,1,3,,SC Cham,FC Zürich II,0,1
Sa 19.11.2016,FC Tuggen,FC Basel 1893 II,1,3,,SC Cham,FC Zürich II,0,1,,SC Kriens,FC Köniz,3,1
Sa 26.11.2016,FC Bavois,SC Brühl,1,4
Mi 30.11.2016,FC Zürich II,FC Basel 1893 II,2,2

最新更新