String durchsuchen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Dienstag 11. September 2012, 17:14

Hallo Leute,

ich habe folgendes vor:
ich möchte ein String nach einem bestimmten Wort durchsuchen lassen.
Hinter dem Wort kommen aber noch je nach Quelle unterschiedliche viele Ziffern und zum Schluss eine Klammer ")" und danach kommen wieder buchstaben.
Alle Zeichenfolgen Vor, innerhalb des Gesuchten, und Nach dem Gesuchten varieren in der Anzahl der Zeichen.

Ich habe eine Möglichkeit mir zurecht geschustert wie es funktioniert
ABER
gibt es noch eine einfachere und kürzere oder intelligentere Art und Weise als meine Überlegung?

BSP: [getestet]

Code: Alles auswählen

>>> a = 'pw try oks Key 1.0.0 (120) tst kw'
>>> b = a.find('Key')
>>> c = a.find(')') + 1
>>> d = a[b:c]
>>> print d
Key 1.0.0 (120)
oder

BSP2: [getestet]

Code: Alles auswählen

>>> a = 'pw try oks Key 1.0.0 (120) tst kw'
>>> b = a[a.find('Key'):a.find(')')+1]
>>> print b
Key 1.0.0 (120)
sieht beides iwie nicht sehr professionell aus :roll:
Zuletzt geändert von OttoPython am Dienstag 11. September 2012, 17:41, insgesamt 1-mal geändert.
"Im Burnout steckt viel Arbeit drin" -Lysander
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Dienstag 11. September 2012, 17:37

Nun, wenn du es kuerzer haben willst, gibt es immernoch regulaere Ausdruecke:

Code: Alles auswählen

In [1]: a = 'pw try oks Key 1.0.0 (120) tst kw'

In [2]: import re

In [3]: re.findall(r'(Key.*?\))', a)
Out[3]: ['Key 1.0.0 (120)']
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Donnerstag 13. September 2012, 08:52

cool.. danke

kannst du mir aber den Ausdruck (Key.*?\)) erklären?
und mit welcher ausgabe kann ich besser weiter arbeiten (meine oder deine)? ich benötige dieses gefundene zum späteren vergleich. das ganze stellt nämlich Versionsnummern eines Programms da.. welche in Datendateien geschrieben sind und ich muss die versionsnummern auf gleichheit prüfen bevor ich mein hauptskrippt starten und an den dateien arbeiten kann.
"Im Burnout steckt viel Arbeit drin" -Lysander
BlackJack

Donnerstag 13. September 2012, 09:22

@OttoPython: Die äusseren Klammern erzeugen eine Gruppe — damit kann man bei `findall()` beeinflussen was im Ergebnis auftaucht, obwohl das in diesem Fall nicht nötig ist. Man könnte die erste Klammer zum Beispiel hinter 'Key' verschieben, wenn man diesen festen Bestandteil nicht im Ergebnis haben möchte:

Code: Alles auswählen

In [56]: re.findall(r'Key (.*?\))', a)
Out[56]: ['1.0.0 (120)']
'Key' erkennt genau die Zeichenfolge 'Key'. Gefolgt von beliebigen Zeichen ('.'), beliebig oft (inklusive gar nicht) ('*'), aber so wenig wie möglich („non-greedy”) ('?'), gefolgt von einer schliessenden Klammer ('\)'). Ohne das '?' würde versucht so viele wie möglich Zeichen vor einer schliessenden Klammer zu erkennen. Das macht dann einen Unterschied, wenn mehrere davon in der Zeichenkette vorkommen.

Neben der Dokumentation zum `re`-Modul gibt es in der Python-Dokumentation auch noch ein Howto zu regulären Ausdrücken: http://docs.python.org/howto/regex.html
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Dienstag 18. September 2012, 15:07

hi BlackJack

danke dafür!

habe nun aber ein kleines Problem.. ich muss nun doch nach 2 Bestimmten Strings suchen, um es zu vereinfachen
nehmen wir das obige Beispiel:

Code: Alles auswählen

import re
a = 'pw try oks Key 1.0.0 (120) tst kw'
re.findall(r'(Key.*?\))', a)
nun muss ich aber nicht nur nach 'Key' sondern auch nach 'ikey' suchen... das Problem an der Sache ist, dass das k bei dem ikey wirklich klein geschrieben wird. Nehme ich die funktion re.findall findet python nun aber nichts.. case sensitivity.. kann ich das irgendwie ändern, dass Python nicht case sensitive ist? also das ich nach nem großen 'K' als auch kleinen 'k' suchen lassen kann?!

beste Grüße
"Im Burnout steckt viel Arbeit drin" -Lysander
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Dienstag 18. September 2012, 15:10

Entweder du veränderst den regulären Ausdruck oder nutzt das Flag re.IGNORECASE beim Durchsuchen. Es steckt alles in der Doku drin.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Dienstag 18. September 2012, 15:27

Code: Alles auswählen

In [1]: import re

In [2]: a = 'pw try oks Key 1.0.0 (120) tst kw, ikey foo bar (123)'

In [3]: re.findall(r'(?:Key|ikey).*?\)', a)
Out[3]: ['Key 1.0.0 (120)', 'ikey foo bar (123)']
Konzept: Non-capturing groups.

Wenn du RE benutzt, solltest du dich aber wirklich zumindest mit der Dokumentation von `re` beschaeftigen (die Dokumentation hat noch ein weitergehendes Tutorial), besser noch mit der Theorie dahinter beschaeftigen.
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Mittwoch 19. September 2012, 07:55

dankeschön!
funktioniert!

ja werde ich mir mal anschauen.. ist wirklich hilfreich.. mit re habe ich vorher noch gar nicht gearbeitet. wird wohl zeit mir das mal zu gemüte zu führen.
"Im Burnout steckt viel Arbeit drin" -Lysander
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Mittwoch 19. September 2012, 11:25

gibt es die Möglichkeit zum Beispiel wenn meine Liste so aussieht:

Code: Alles auswählen

a = ['try Key 1.0.0 (1026); bla']
nach dem ';' zu suchen aber bis zu der stelle davor auszugeben? mit meinem allerersten versuch über das .find war das ja möglich aber in der doku zu re habe ich dazu nichts gefunden.

anderer Gedanke meinerseits war
da die Unterscheidung zwischen Key und ikey eh getroffen wird und die Liste mit Key ein '()' enthält und die Liste von ikey nur ';' also keine Klammern enthält nach beiden Suchen zu lassen und dann was er findet bis dahin die ausgabe macht.

meine Überlegung dazu hatte ich in der doku zum re.search gesehen bei dem eine Unterscheidung durch [);] mögliche wäre
aber baue ich das in den befehl ein:

Code: Alles auswählen

re.findall(r'(?:Key|ikey).+?\(?:)|;)',b)

Code: Alles auswählen

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\re.py", line 177, in f
    return _compile(pattern, flags).findall(st
  File "C:\Python27\lib\re.py", line 244, in _
    raise error, v # invalid expression
sre_constants.error: unbalanced parenthesis
was tun? beide Ansätze bekomme ich nicht gelöst
"Im Burnout steckt viel Arbeit drin" -Lysander
BlackJack

Mittwoch 19. September 2012, 12:03

@OttoPython: Du kommst da mit den Klammern durcheinander. Klammern die zum regulären Ausdruck gehören, also nicht durch einen '\' davon befreit sind, müssen in korrekt verschachtelt in Paaren auftreten. Denn sie kapseln ja einen Teilausdruck. Du hast da zwei schliessende Klammern für die es kein Gegenstück gibt, wo der geklammerte Teilausdruck anfangen würde.

Das bei 'ikey' keine Klammern sondern ein ';' den gesuchten Teil abschliesst, ist jetzt eine neue Bedingung oder? Gibt es das Semikolon auch immer bei 'Key'? Also könnte man die Klammern komplett ignorieren und immer bis zu einem ';' suchen?

Bei solchen Sachen ist es in der Regel besser sich zuerst klar zu machen wie *alle* Variationen aussehen können, die man suchen möchte, und *dafür* einen regulären Ausdruck zu entwickeln, als immer mit neuen Bedingung und Randfällen anzukommen und einen Ausdruck zu erweitern. Ist natürlich nicht immer möglich, vor allem wenn man neue Bedingungen selber erst beim Auswerten der Daten findet.

Wenn Du etwas nicht mit Ergebnis von `findall()` haben möchtest, dann muss es halt einfach ausserhalb der („capturing”) Gruppe stehen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mittwoch 19. September 2012, 13:26

Nehm dir BlackJacks Post zu Herzen und besonders unterstuetze ich, dass du RE nicht stueckweise zusammenbaust, sondern erst das ganze Bild betrachtest.

Der richtige Ausdruck sollte dieser sein:

Code: Alles auswählen

r'(?:Key|ikey).+?(?:\)|;)'
Klammern sind Teil der RE Metasprache (wie z.B. + und ?), willst du wirklich eine Klammer matchen muss es \) heissen. Du hast das genau verdreht.
Benutzeravatar
OttoPython
User
Beiträge: 47
Registriert: Montag 23. April 2012, 14:14

Mittwoch 19. September 2012, 13:31

Hey danke,

also es ist wirklich der Fall das bei beiden 'Key' und 'ikey' ein Simikolon folgt und nur der eine Fall ohne eine Klammer davor endet. Ich habe ja bereits bis zum Simikolon für mich suchen lassen nur mich hat halt das Simikolon gestört dass es in der ausgabe mitz drin is..habe jetzt die Lösung =)

Code: Alles auswählen

re.findall(r'((?:Key|ikey).+?)\;',a)
der andere Gedanke kam mir nur in den Sinn ob es überhaupt möglich ist nach 2 unterschiedlichen Sachen bis zu 2 unterschiedlichen Enden suchen zu lassen..


edit:

des rätsel gesammter Lösung wäre dann:

re.findall(r'((?:Key|ikey).+?)(?:\)|;)', a)

das sind wirklich ein haufen informationen in diesen klammern und da muss man auch erstmal genau den überblick haben, was ist jetzt wirklich vom reg. Ausdruck und was will ich dadrin machen.

Danke dafür =)
"Im Burnout steckt viel Arbeit drin" -Lysander
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mittwoch 19. September 2012, 14:34

Na wenn beide Faelle mit `;` enden geht das viel einfacher: r"((?:Key|ikey).+?);"

Da du ; zu einem \; gemacht hast: Rate nicht, sondern schau in die Dokumentation. Hier sind besondere Zeichen aufgelistet: http://docs.python.org/library/re.html
spicer
User
Beiträge: 6
Registriert: Freitag 5. März 2021, 23:40
Kontaktdaten:

Samstag 6. März 2021, 01:40

Hallo Gemeinde
Ich hole diesen alten Thread mal aus der Versenkung ^^
Aber das passt genau da rein (hoffe ich. Sonst einfach verschieben bitte).
Das Vorherige handelt wahrscheinlich von Python2. Hier aber ist Python3 an der Reihe.

loc.sun(date.today()).items()

gibt folgendes aus:

dict_items([('sunset', datetime.datetime(2021, 3, 5, 18, 22, 39, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>)), ('dawn', datetime.datetime(2021, 3, 5, 6, 30, 14, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>)), ('noon', datetime.datetime(2021, 3, 5, 12, 41, 39, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>)), ('dusk', datetime.datetime(2021, 3, 5, 18, 53, 3, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>)), ('sunrise', datetime.datetime(2021, 3, 5, 7, 0, 38, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>))])

Das nächste mal:

dict_items([('noon', datetime.datetime(2021, 3, 5, 12, 41, 39, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>)), ('dawn', datetime.datetime(2021, 3, 5, 6, 30, 14, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>)), ('sunrise', datetime.datetime(2021, 3, 5, 7, 0, 38, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>)), ('sunset', datetime.datetime(2021, 3, 5, 18, 22, 39, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>)), ('dusk', datetime.datetime(2021, 3, 5, 18, 53, 3, tzinfo=<DstTzInfo 'Europe/Zurich' CET+1:00:00 STD>))])

Die Reihenfolge von sunrise und sunset ist immer anders.

Darum gibt mir:

sun1 = str(list(data)[1])
zeit = sun1.split(', ')
print(zeit[4] + ":" + zeit[5])

immer eine andere, falsche Zeit aus.
Wie bewerkstellige ich es, dass vor dem lesen der Zeit (Zahl 4 und 5) zuerst auf den vorangehenden Text sunrise bzw sunset geachtet wird?
Vorher mit Python2 funktionierte das ohne den list Befehl. Mit Python3 leider nicht mehr und man braucht den list Befehl, welcher aber nicht mehr gleich reagiert.
Früher sah die Zeile so aus:

sun1 = str(data[1])

Habe nun mit

import re
d = re.findall(r"sunset', datetime.datetime\((.*?tzinfo)", str(zeit))

versucht. Aber das bringt mich auch nicht zur Lösung.


Ich hoffe, ich konnte das Problem einigermassen verständlich beschreiben. Ist gar nicht so einfach ^^

Danke schonmal im Voraus und ich freue mich, ein Teil dieser Community zu sein. Die Avatar Restriktionen sind zu bissig. Darum hab ich noch keinen passenden gefunden.
Benutzeravatar
sparrow
User
Beiträge: 2639
Registriert: Freitag 17. April 2009, 10:28

Samstag 6. März 2021, 09:08

Das ist doch eine Datenstruktur und keine Zeichenkette. Warum wandelst du die denn in eine Zeiuchenkette und versucht dann Zeichenkettenoperationen drauf?

Es handelt sich um ein dictionary. Und darin befindet sich eine Zeichenkette ("sunset", "noon", ...) als Schlüssel und datetime.datetime-Objekt als Wert.
Schau dir mal an, was dicts sind und wie sie funktionieren.
Antworten