2015-06-03 15 views
5

Ich benutze Python Regex, um bestimmte Werte aus einer gegebenen Zeichenfolge zu extrahieren. Das ist mein string:Python: regex findall

mystring.txt

sometext 
somemore text here 

some other text 

       course: course1 
Id    Name    marks 
____________________________________________________ 
1    student1   65 
2    student2   75 
3    MyName    69 
4    student4   43 

       course: course2 
Id    Name    marks 
____________________________________________________ 
1    student1   84 
2    student2   73 
8    student7   99 
4    student4   32 

       course: course4 
Id    Name    marks 
____________________________________________________ 
1    student1   97 
3    MyName    60 
8    student6   82 

und ich brauche die Kursnamen und entsprechende Markierungen für einen bestimmten Schüler zu extrahieren. Zum Beispiel brauche ich den Kurs und die Markierungen für MyName aus dem obigen String.

Ich habe versucht:

re.findall(".*?course: (\w+).*?MyName\s+(\d+).*?",buff,re.DOTALL) 

Das funktioniert aber nur, wenn MyName vorhanden unter jedem Kurs ist, aber nicht, wenn MyName wird in einigen der natürlich, wie in meinem Beispiel Zeichenfolge fehlt.

Hier bekomme ich Ausgang als: [('course1', '69'), ('course2', '60')]

aber was eigentlich das, was ich will achive ist: [('course1', '69'), ('course4', '60')]

, was die richtige regex hierfür wäre?

#!/usr/bin/python  
import re 

buffer_fp = open("mystring.txt","r+") 
buff = buffer_fp.read() 
buffer_fp.close() 
print re.findall(".*?course: (\w+).*?MyName\s+(\d+).*?",buff,re.DOTALL) 

Antwort

5
.*?course: (\w+)(?:(?!\bcourse\b).)*MyName\s+(\d+).*? 

        ^^^^^^^^^^^^ 

können Sie versuchen, this.See demo.Just einen Look-Ahead-basierten quantifier verwenden, die für MyName vor einem course, kurz bevor er sucht.

https://regex101.com/r/pG1kU1/26

+0

Danke für die Antwort! – Deepa

+0

was sind die g, s und flags? Ich verstehe s ist gleichbedeutend mit neu zu zeichnen. Ich dachte, g ist für findall, aber dann mit dieser Regex in Python-Code gibt eine andere Ausgabe – Deepa

+0

Aber re.findall (". *? Kurs: (\ w +) (?: (?! \ Bcourse \ b).) * MeinName \ s + (\ d +). *? ", Buff, re.DOTALL) Ausgaben: [('Kurs1', '60')] :( – Deepa

2

Ich vermute, dies unmöglich ist, in einem einzigen regulären Ausdruck zu tun. Sie sind nicht allmächtig.

Auch wenn Sie einen Weg finden, tun Sie dies nicht. Ihre nicht funktionierende Regex ist schon fast unlesbar; Eine funktionierende Lösung wird wahrscheinlich noch mehr sein. Sie können dies wahrscheinlich in nur wenigen Zeilen aussagekräftigen Codes tun. Pseudo-Code-Lösung:

for line in buff: 
    if it is a course line: 
     set the course variable 
    if it is a MyName line: 
     add (course, marks) to the list of matches 

Beachten Sie, dass dies könnte (und wahrscheinlich sollte) umfassen reguläre Ausdrücke in jeder von denen, wenn Blöcke. Es ist nicht der Fall, zwischen dem Hammer und dem Schraubenzieher zu wählen, um den anderen auszuschließen, sondern beide für das zu verwenden, was sie am besten können.

+0

Raten Sie unterschätzten Regex :) – vks

+1

@vks Ich denke, ich habe es getan. Aber respektvoll beweist deine Lösung meinen Standpunkt. Diese Regex ist unleserlicher Müll - viel Glück für die OP, wenn sich ihre Anforderungen ändern und sie versuchen müssen, es zu beheben. Es liest sich mehr wie Perl als Python. –

+0

es ist unleserlicher Müll für den, der es nicht verstehen kann :) – vks