如何解析文本文件并将行保存为dict作为键和值列表

时间:2019-05-02 09:46:23

标签: python

我正在尝试解析许多“ .txt”文件,并将某些行作为键存储,而另一些行作为值存储在字典中。 方法应尽可能抽象,因为整个文件的文件结构是相同的,但某些记录可以具有比其他记录更少或更多的字段,而同一记录可以具有更少或更多的行在不同的记录中。

文本文件格式如下,但通常具有或多或少的属性:

Autore principale:
     Christie, Agatha
Titolo:
     La mia vita / Agatha Christie ; traduzione di Maria Giulia Castagnone
Pubblicazione:
     Milano : Oscar Mondadori, 1995
Descrizione fisica:
     636 p. ; 20 cm.
Collezione:
    Oscar narrativa ; 1563
        Oscar scrittori moderni
Titolo uniforme:
    An autobiography | Christie, Agatha
Numeri:
    [ISBN]  978-88-04-52225-6 9. rist. 2013
Nomi:
     Christie, Agatha
        [Traduttore]  Castagnone, Mariagiulia
Soggetti:
    Christie, Agatha
Classificazione Dewey:
    823.912 (19.) NARRATIVA INGLESE. 1900-1945
Lingua di pubblicazione:
    ita
Paese di pubblicazione:
    IT
Codice identificativo:
    IT\ICCU\LIA\0962595

每行以':'结尾的行应该是一个键,而下一个(有时也可以是以下一个,如您所见)是一个值列表那个钥匙。

预期输出:

{'Autore principale:': ['Christie, Agatha'],
 'Titolo:': ['\x88La \x89mia vita / Agatha Christie ; traduzione di Maria Giulia Castagnone'],
 'Pubblicazione:': ['Milano : Oscar Mondadori, 1995'],
 'Descrizione fisica:': ['636 p. ; 20 cm.'],
 'Collezione:': ['Oscar narrativa ; 1563', 'Oscar scrittori moderni'],
 'Titolo uniforme:': ['\x88An \x89autobiography | Christie, Agatha'],
 'Numeri:': ['[ISBN]  978-88-04-52225-6 9. rist. 2013'],
 'Nomi:': ['Christie, Agatha'],
...
...}

到目前为止,我已经来到了这个python代码:


with open('file.txt', 'r', encoding='utf-8', errors='ignore') as f:
    lines = [line.strip() for line in f.readlines()]
    record_keys = [elem for elem in lines if elem.endswith(':')]

    # here comes the loop:
    length = len(lines) 
    i = 0
    values = []
    while i < length:
        if lines[i] in record_keys:
            current_key = record_keys.index(lines[i])
            i+=1
        else:
            if lines[i] == lines[-1]:
                val = [i for i in lines[lines.index(lines[i]):]]
                values.append(val)
                i+=1
            else:
                if len(values) > 0 and lines[i] in values[-1]:
                    print({f'string {lines[i]}} already in [values], skipping')
                    i+=1
                else:
                    next_key = record_keys[current_key+1]
                    val = [i for i in lines[lines.index(lines[i]):lines.index(next_key)]]
                    values.append(val)
                    i+=1

    # dict from zip object
    isbn_dict = dict(zip(record_keys, values))

我收到此错误:

IndexError: list index out of range

结果字典:

{'Autore principale:': ['Christie, Agatha'],
 'Titolo:': ['\x88La \x89mia vita / Agatha Christie ; traduzione di Maria Giulia Castagnone'],
 'Pubblicazione:': ['Milano : Oscar Mondadori, 1995'],
 'Descrizione fisica:': ['636 p. ; 20 cm.'],
 'Collezione:': ['Oscar narrativa ; 1563', 'Oscar scrittori moderni'],
 'Titolo uniforme:': ['\x88An \x89autobiography | Christie, Agatha'],
 'Numeri:': ['[ISBN]  978-88-04-52225-6 9. rist. 2013'],
 'Nomi:': ['Christie, Agatha',
  'Titolo:',
  '\x88La \x89mia vita / Agatha Christie ; traduzione di Maria Giulia Castagnone',
  'Pubblicazione:',
  'Milano : Oscar Mondadori, 1995',
  'Descrizione fisica:',
  '636 p. ; 20 cm.',
  'Collezione:',
  'Oscar narrativa ; 1563',
  'Oscar scrittori moderni',
  'Titolo uniforme:',
  '\x88An \x89autobiography | Christie, Agatha',
  'Numeri:',
  '[ISBN]  978-88-04-52225-6 9. rist. 2013',
  'Nomi:',
  'Christie, Agatha',
  '[Traduttore]  Castagnone, Mariagiulia'],
 'Soggetti:': ['823.912 (19.) NARRATIVA INGLESE. 1900-1945'],
 'Classificazione Dewey:': ['ita'],
 'Lingua di pubblicazione:': ['IT'],
 'Paese di pubblicazione:': ['IT\\ICCU\\LIA\\0962595']}

结果是一团糟,可能是由块中的某物引起的:

else:
    if len(values) > 0 and lines[i] in values[-1]:
        print({f'string {lines[i]}} already in [values], skipping')
        i+=1

任何帮助将不胜感激,谢谢

2 个答案:

答案 0 :(得分:2)

这是应该解决的问题:

with open('t6.txt', 'r', encoding='utf-8', errors='ignore') as f:
    lines = [line.strip() for line in f.readlines()]
    d = {}
    keys = []
    vals = []
    for line in lines:
        if line.endswith(':'):
            keys.append(line)
        else:
            vals.append(line)
    for k in keys[:-1]:
        d[k] = lines[lines.index(k)+1:lines.index(keys[keys.index(k)+1])]
    print(d)

输出

{'Autore principale:': ['Christie, Agatha'], 
'Titolo:': ['La mia vita / Agatha Christie ; traduzione di Maria Giulia Castagnone'], 
'Pubblicazione:': ['Milano : Oscar Mondadori, 1995'], 
'Descrizione fisica:': ['636 p. ; 20 cm.'], 
'Collezione:': ['Oscar narrativa ; 1563', 'Oscar scrittori moderni'], 
'Titolo uniforme:': ['An autobiography | Christie, Agatha'], 
'Numeri:': ['[ISBN]  978-88-04-52225-6 9. rist. 2013'], 
'Nomi:': ['Christie, Agatha', '[Traduttore]  Castagnone, Mariagiulia'], 
'Soggetti:': ['Christie, Agatha'], 
'Classificazione Dewey:': ['823.912 (19.) NARRATIVA INGLESE. 1900-1945'], 
'Lingua di pubblicazione:': ['ita'], 
'Paese di pubblicazione:': ['IT']}

答案 1 :(得分:0)

作为一种好的做法,应避免循环“索引”,而应使用dict理解和for-each循环:

with open('file.txt', 'r', encoding='utf-8', errors='ignore') as f:
    lines = [line.strip() for line in f.readlines()]
    record_keys = { elem for elem in lines if elem.endswith(':') } # a set
    isbn_dict = { elem : set() for elem in record_keys }   # a dict of sets

    current_key = None
    for line in lines:
        if line in record_keys:
            current_key = line
        else:
            isbn_dict[current_key].add(line)