Voici ma réponse provisoire, pas que j'en sois fier. J'ai criblé un morceau de https://stackoverflow.com/a/5824309/131187.
>>> import pyparsing as pp
>>> pp.ParserElement.setDefaultWhitespaceChars(" \t")
>>> EOL = pp.LineEnd().suppress()
>>> keyword = pp.Or([pp.Keyword('Projects'), pp.Keyword('Education')])
>>> line = pp.LineStart() + pp.NotAny(keyword) + pp.SkipTo(pp.LineEnd(), failOn=pp.LineStart()+pp.LineEnd()) + EOL
>>> lines = pp.OneOrMore(line)
>>> section = pp.Or([pp.Keyword('Projects'), pp.Keyword('Education')])('section') + EOL + lines('lines')
>>> sections = pp.OneOrMore(section)
>>> r = sections.parseString(input_text)
Comme vous pouvez le voir juste en dessous de cette phrase, l'analyseur parvient à recueillir correctement les informations, et dans la collecte de telle manière qu'il puisse être assemblé, comme nous allons le montrer. Cependant, je ne peux pas trouver un moyen d'accéder à tous les résultats de parseString
qui sont si clairement disponibles. J'ai appliqué le eval
à sa représentation repr
. Ayant fait cela, j'ai été en mesure de choisir toutes les pièces et les assigner à un objet semblable à un dict.
Pour être honnête, ce serait plus facile à faire sans pyparsing. Lisez une ligne, notez s'il s'agit d'un mot-clé. Si c'est le cas, souvenez-vous-en. Ensuite, jusqu'à ce que vous lisiez un autre mot-clé, placez toutes les lignes que vous lisez dans un dictionnaire sous le mot-clé le plus récent.
>>> repr(r)
"(['Projects', 'project 1', 'project 2', 'project 3', '', 'Education', 'institution 1', 'institution 2', 'institution 3', 'institution 4', '', 'Projects', 'assignment 5', 'assignment 8', 'assignment 10', ''], {'lines': [(['project 1', 'project 2', 'project 3', ''], {}), (['institution 1', 'institution 2', 'institution 3', 'institution 4', ''], {}), (['assignment 5', 'assignment 8', 'assignment 10', ''], {})], 'section': ['Projects', 'Education', 'Projects']})"
>>> evil_r = eval(repr(r))
>>> evil_r
(['Projects', 'project 1', 'project 2', 'project 3', '', 'Education', 'institution 1', 'institution 2', 'institution 3', 'institution 4', '', 'Projects', 'assignment 5', 'assignment 8', 'assignment 10', ''], {'lines': [(['project 1', 'project 2', 'project 3', ''], {}), (['institution 1', 'institution 2', 'institution 3', 'institution 4', ''], {}), (['assignment 5', 'assignment 8', 'assignment 10', ''], {})], 'section': ['Projects', 'Education', 'Projects']})
>>> evil_r[1]['lines']
[(['project 1', 'project 2', 'project 3', ''], {}), (['institution 1', 'institution 2', 'institution 3', 'institution 4', ''], {}), (['assignment 5', 'assignment 8', 'assignment 10', ''], {})]
>>> evil_r[1]['section']
['Projects', 'Education', 'Projects']
>>> from collections import defaultdict
>>> section_info = defaultdict(list)
>>> for k, kind in enumerate(evil_r[1]['section']):
... section_info[kind].extend(evil_r[1]['lines'][k][0][:-1])
>>> for section in section_info:
... section, section_info[section]
...
('Education', ['institution 1', 'institution 2', 'institution 3', 'institution 4'])
('Projects', ['project 1', 'project 2', 'project 3', 'assignment 5', 'assignment 8', 'assignment 10'])
EDIT: Ou vous pouvez le faire. Besoin de rangement. Au moins, il n'utilise rien de peu orthodoxe.
>>> input_text = open('temp.txt').read()
>>> import pyparsing as pp
>>> pp.ParserElement.setDefaultWhitespaceChars(" \t")
>>> from collections import defaultdict
>>> class Accum:
... def __init__(self):
... self.current_section = None
... self.result = defaultdict(list)
... def __call__(self, s):
... if s[0] in ['Projects', 'Education']:
... self.current_section = s[0]
... else:
... self.result[self.current_section].extend(s[:-1])
...
>>> accum = Accum()
>>> EOL = pp.LineEnd().suppress()
>>> keyword = pp.Or([pp.Keyword('Projects'), pp.Keyword('Education')])
>>> line = pp.LineStart() + pp.NotAny(keyword) + pp.SkipTo(pp.LineEnd(), failOn=pp.LineStart()+pp.LineEnd()) + EOL
>>> lines = pp.OneOrMore(line)
>>> section = pp.Or([pp.Keyword('Projects'), pp.Keyword('Education')]).setParseAction(accum) + EOL + lines.setParseAction(accum)
>>> sections = pp.OneOrMore(section)
>>> r = sections.parseString(input_text)
>>> accum.result['Education']
['institution 1', 'institution 2', 'institution 3', 'institution 4']
>>> accum.result['Projects']
['project 1', 'project 2', 'project 3', 'assignment 5', 'assignment 8', 'assignment 10']
Une section "Projets" peut-elle contenir plus d'une ligne décrivant un projet? Et de même pour les sections 'Education'? –
Dans vos appels à 'setResultsName' sur project_section et education_section, ajoutez' listAllMatches = True'. Ensuite, je pense que votre code fonctionnera tel quel. – PaulMcG
@PaulMcG Ajouter 'listAllMatches = True' regroupe les résultats, merci! –