Benutzereingabe und das Modul re

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
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

Hallo Python-Gemeinde,
ich habe leider noch keine Lösung gefunden, wie ich eine Benutzereingabe eines r-Strings mit re.search verarbeiten kann.
hier ein pZeilen Code dazu:

Code: Alles auswählen

import re

def regChecker () :
    teststring = input ("bitte gebe deinen zu überprüfenden String ein :  ")
    while teststring :
        ra = input ("bitte gebe deinen regulären Ausdruck ein :  ")
        if not ra :
            break
        if re.search (ra, teststring) :
            print ("match !")
            teststring = input ("bitte gebe deinen zu überprüfenden String ein :  ")
        else :
            print ("no matching !")

regChecker ()

if(__name__ == "__main__"):
    print ()
    print ("Programm schliessen mit <Enter>")


Programmablauf :
bitte gebe deinen zu überprüfenden String ein : Er ist deutsch und wird Mayer genannt.
bitte gebe deinen regulären Ausdruck ein : r"M[ae][iy]er"
no matching !
bitte gebe deinen regulären Ausdruck ein :

Programm schliessen mit <Enter>


Wenn ich nun aber den r-String direkt im Script eingebe :

Code: Alles auswählen

import re

def regChecker () :
    teststring = input ("bitte gebe deinen zu überprüfenden String ein :  ")
    while teststring :
##        ra = input ("bitte gebe deinen regulären Ausdruck ein :  ")
##        if not ra :
##            break
        if re.search (r"M[ae][iy]er", teststring) :
            print ("match !")
##            teststring = input ("bitte gebe deinen zu überprüfenden String ein :  ")
            [b]teststring = ""[/b]           ## Unterbindung einer Endlosschleife
        else :
            print ("no matching !")

regChecker ()

if(__name__ == "__main__"):
    print ()
    print ("Programm schliessen mit <Enter>")
Programmablauf :
bitte gebe deinen zu überprüfenden String ein : Er ist deutsch und wird Mayer genannt.
match !

Programm schliessen mit <Enter>


Hat jemand von Euch einen Vorschlag oder gar Lösung ?

Im Voraus besten Dank !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Die Lösung ist keinen ”r-String” eingeben zu wollen. Das macht keinen Sinn. Da wo der Benutzer den regulären Ausdruck eingaben soll, muss er nur den regulären Ausdruck eingeben, nicht irgendwelchen Python-Code für eine raw-Zeichenkette. Das r" am Anfang und das " am Ende gehört da nicht hin, denn das soll ja gar nicht *in* der Zeichenkette erscheinen.

Die Bedingung der ``while``-Schleife ist zudem ungünstig. Das sollte einfach eine ”Endlosschleife” mit ``while True:`` sein und nicht von dem Inhalt von `teststring` abhängen. Dann braucht man den auch nur an *einer* Stelle im Code vom Benutzer abfragen.

Der Aufruf von `regchecker()` erfolgt *bevor* dem Benutzer der Hinweis ausgegeben wird, der im ``if __name__ …``-Zweig steht. Bei dem ``if`` gehören auch keine Klammern um die Bedingung.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@_blackjack_ :
danke für die schnelle Antwort :D

wenn ich nun aber keinen r-String eingeben soll, dann muß ich alles escapen (was escape-würdig ist), also anstelle von "\" muß ich "\\" usw. als regex eingeben. Das kann bei langen regexen zur Unübersichtlichkeit führen und das Ganze unleserlicher machen ... dies ist eben der Sinn eines r-Strings ;-)

ich finde die Bedingung mit der while-Schleife eigentlich gut, da bei falscher Regex nicht jedes mal erneut der zu überprüfende String eingegeben werden muß, oder verstehe ich jetzt etwas falsch ? Siehe dazu neuer Code ...

meine Überlegung zu

Code: Alles auswählen

if __name__ == "__main__" :
war folgender: wird das Programm in der Console ausgeführt, bleibt das Consolen-Fenster geöffnet und verschwindet nicht sofort ;-) ...

Code:

Code: Alles auswählen

from re import *

def regChecker () :
    teststring = input ("bitte gebe deinen zu überprüfenden String ein :  ")
    while teststring :
        ra = input ("bitte gebe deinen regulären Ausdruck ein :  ")
        if not ra :
            break
        re = compile (ra)
        x = str (re.search (teststring))
        ausgabe = x [17 : -1]
        if re.search (teststring) :
            print (">>> ", ausgabe)
            teststring = input ("bitte gebe deinen zu überprüfenden String ein :  ")
        else :
            print ("no matching !")
    print ("\ndanke, dass du meinen regex-checker verwendet hast !")

regChecker ()

if __name__ == "__main__" :
    print ()
    print ("Programm schliessen mit <Enter>")
Programmablauf :

bitte gebe deinen zu überprüfenden String ein : 67\78
bitte gebe deinen regulären Ausdruck ein : \\
>>> span=(2, 3), match='\\'
bitte gebe deinen zu überprüfenden String ein : er heißt Meyer
bitte gebe deinen regulären Ausdruck ein : M[ea][iy]er
>>> span=(9, 14), match='Meyer'
bitte gebe deinen zu überprüfenden String ein : eine Katze miaut.
bitte gebe deinen regulären Ausdruck ein : Kuh
no matching !
bitte gebe deinen regulären Ausdruck ein : Katze
>>> span=(5, 10), match='Katze'
bitte gebe deinen zu überprüfenden String ein :

danke, dass du meinen regex-checker verwendet hast !

Programm schliessen mit <Enter>

hat noch jemand eine Idee, wie ich einen r-String in diesem Script verwenden kann ?
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: r-Zeichenketten sind nur etwas im Python-Quelltext. Das hat nichts mit Benutzereingaben zu tun. Und auch dort musst Du für reguläre Ausdrücke spezielle Zeichen für reguläre Ausdrücke escapen. Aber eben nur für den regulären Ausdruck und nicht noch einmal für Python's Compiler. Um einen Backslash zu matchen musst Du immer *zwei* eingeben, auch bei einer r-Zeichenkette. Um *einen* \ zu matchen muss die Zeichenkette im Python-Quelltext entweder so aussehen: r'\\' oder aber ohne das r so: '\\\\'. Beide Zeichenketten enthalten genau zwei \:

Code: Alles auswählen

In [1]: len(r'\\')
Out[1]: 2

In [2]: print(r'\\')
\\

In [3]: len('\\\\')
Out[3]: 2

In [4]: print('\\\\')
\\

In [5]: r'\\' == '\\\\'
Out[5]: True
Die Bedingung ist auch für den Fall nicht gut, weil viel zu unübersichtlich, und wie gesagt, hast Du den Code für die Abfrage *zweimal* im Quelltext stehen. Das verletzt das DRY-Prinzip (Don't Repeat Yourself). Wenn man Code oder Daten mehrfach im Quelltext stehen hat, ist das fehleranfälliger wenn man etwas ändern will oder muss, weil man das dann an jeder Stelle wo es vorkommt, verändern muss. Dabei besteht die Gefahr das man nicht alle Stellen ändert, oder nicht alle gleich ändert. Die äussere ``while``-Schleife ist dazu da den gesamten Vorgang zu wiederholen. Wenn Du die Eingabe eines regulären Ausdrucks auch wiederholen möchtest, dann sollte das an der Stelle wo es wiederholt werden soll, in einer eigenen Schleife passieren, damit man diese Absicht auch leicht am Quelltext ablesen kann.

Bei den regulären Ausdrücken möchtest Du vielleicht auch auf Fehleingaben reagieren, denn es ist ja nicht schwer auch mal syntaktisch nicht korrekte reguläre Ausdrücke einzugeben, und dann sollte das Programm vielleicht nicht einfach abbrechen, sondern den Benutzer auch diese Eingabe wiederholen lassen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Man kann keine r-Strings "eingeben". r-Strings sind einzig und alleine eine Sache des Python Lexers, der deinen Quellcode verarbeitet. Du musst auf der anderen Seite aber auch ueberhaupt nichts extra escapen, denn diese Notwendigkeit ist AUCH nur eine, die der Python-Lexer von dir verlangt. Denn der will ja aus \n ein newline machen.

Folgendes Programm

Code: Alles auswählen

import re
rex = input("rex eingeben:")
eingabe = "..A"
print(re.match(rex, eingabe))
funktioniert zB mit Eingabe

...
..A

aber nicht

..\.
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Oder, um das auch noch mal deutlich zu machen:

Code: Alles auswählen

print(input("eingabe:"))
genutzt in der Shell

Code: Alles auswählen

$ python3 /tmp/test.py 
eingabe:\t
\t
Du hast also keine escapes. Woher auch?
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Weitere Anmerkungen: Sternchen-Importe sind Böse™. Du holst Dir damit alle möglichen Namen aus dem Modul in Deinen Modulnamensraum, in der Regel ohne zu wissen welche das alles sind, denn wenn der Autor des anderen Moduls nicht explizit Massnahmen ergriffen hat, dann holst Du ja auch alles was dort definiert und selbst importiert wird. So höhlt man das Konzept von Modulen als Trennung aus. Es wird für Leser schwerer nachzuvollziehen was woher kommt, und es besteht zudem die Gefahr von Namenskollisionen.

Wie Du `ausgabe` erstellst ist übrigens nicht robust. Du verlässt Dich da auf eine Zeichenkettendarstellung von Match-Objekten die nicht dafür gedacht ist für eine Ausgabe zurechtgestückelt zu werden. Die Informationen die da enthalten sind, kannst Du auch alle von dem Objekt abfragen und selber passend in eine Zeichenkette formatieren.

`ra` und `x` sind keine guten Namen, wiel die überhaupt nicht vermitteln was die Werte dahinter bedeuten.

`regChecker()` schriebt man in Python `reg_checker()`. Alles ausser Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase) wird klein_mit_unterstrichen geschrieben.

Zwischen einer Funktion/Methode und der öffnenden Klammer der Argumentliste gehört kein Leerzeichen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Hier mal als Code was ich über den Programmfluss/die Organisation der Schleifen geschrieben habe. Ausserdem eine Idee wie man die Informationen aus dem Match-Objekt für eine Ausgabe aufbereiten kann in dem der Treffer ”unterstrichen” angezeigt wird. Zudem mit Abfangen von Fehlern im regulären Ausdruck.

Code: Alles auswählen

#!/usr/bin/env python3
import re


def main():
    while True:
        string = input('Bitte gib Deinen zu überprüfenden String ein: ')
        if not string:
            break
        while True:
            pattern = input('Bitte gib Deinen regulären Ausdruck ein: ')
            if not pattern:
                break
            try:
                match = re.search(pattern, string)
            except re.error as error:
                print(error)
            else:
                if match:
                    start, end = match.span()
                    print(string)
                    print(' ' * start + '^' * (end - start))
                    break
                else:
                    print('Kein Treffer!')
            
    print('\nDanke, dass du meinen Regex-Checker verwendet hast!')


if __name__ == '__main__':
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
Danke für deine schnelle Antwort :-)
Um einen Backslash zu matchen musst Du immer *zwei* eingeben, auch bei einer r-Zeichenkette.
ok, verstanden. Aber jetzt kommt wieder ein Punkt, der mich schier verzweifeln läßt :
Um *einen* \ zu matchen muss die Zeichenkette im Python-Quelltext entweder so aussehen: r'\\' oder aber ohne das r so: '\\\\'. Beide Zeichenketten enthalten genau zwei \:
Hast du dich vertippt? Sollte es nicht heißen:
"um *zwei* \ zu matchen [...]
Die Bedingung ist auch für den Fall nicht gut, weil viel zu unübersichtlich, und wie gesagt, hast Du den Code für die Abfrage *zweimal* im Quelltext stehen. Das verletzt das DRY-Prinzip (Don't Repeat Yourself).
DRY habe ich verstanden :-) Dann werde ich eine zweite Schleife einbauen - kein Thema. Hatte ich aus dem Buch "Python 3 - lernen und PROFESSIONELL anweden". Vielleicht lese ich ja die falschen Bücher :-(
Bei den regulären Ausdrücken möchtest Du vielleicht auch auf Fehleingaben reagieren, denn es ist ja nicht schwer auch mal syntaktisch nicht korrekte reguläre Ausdrücke einzugeben, und dann sollte das Programm vielleicht nicht einfach abbrechen, sondern den Benutzer auch diese Eingabe wiederholen lassen.
Das Script bricht ja nur ab, oder sollte nur dann abbrechen, wenn der Benutzer die Enter-Taste drückt, OHNE eine Eingabe zu machen (die Enter-Taste persé mal nicht als Eingabe zu verstehen).
Aber klar, hatte ich bereits bemerkt und werde wohl eine try...except-Anweisung einbauen müssen.
Weitere Anmerkungen: Sternchen-Importe sind Böse.
ok, wenn ich das richtig verstehe, dann werden durch "import [moduname]" die Funktionen/Methoden des entsprechenden Moduls 'nur' zur Verfügung gestellt und nur dann die betreffende Funktion/Methode in den Speicher oder Namensraum geladen, wenn ich sie (durch das Script) aufrufe. Richtig ?
Wie Du `ausgabe` erstellst ist übrigens nicht robust. Du verlässt Dich da auf eine Zeichenkettendarstellung von Match-Objekten die nicht dafür gedacht ist für eine Ausgabe zurechtgestückelt zu werden. Die Informationen die da enthalten sind, kannst Du auch alle von dem Objekt abfragen und selber passend in eine Zeichenkette formatieren.
ich dachte, das hätte ich gemacht; dies war jedenfalls mein Gedanke. Vielleicht kannst du zeigen, wie es richtig geht ?
`ra` und `x` sind keine guten Namen, wiel die überhaupt nicht vermitteln was die Werte dahinter bedeuten.
ok, werde ich definitv ändern, danke !
`regChecker()` schriebt man in Python `reg_checker()`. Alles ausser Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase) wird klein_mit_unterstrichen geschrieben.
Stand als Alternativvorschlag auch in dem Buch. Aber "reg_checker" ist mir auch wesentlich sympathischer :-) werde ich ab sofort auch so handhaben.
Zwischen einer Funktion/Methode und der öffnenden Klammer der Argumentliste gehört kein Leerzeichen.
ok, (im Hirn) gespeichert
Hier mal als Code was ich über den Programmfluss/die Organisation der Schleifen geschrieben habe. Ausserdem eine Idee wie man die Informationen aus dem Match-Objekt für eine Ausgabe aufbereiten kann in dem der Treffer ”unterstrichen” angezeigt wird. Zudem mit Abfangen von Fehlern im regulären Ausdruck.
super, danke. Muß ich aber erst noch durchlesen und begreifen. Damit hat sich meine Bitte von oben erledigt, daaaanke !

@_deets_ :
persönliche Frage:
deets kommt von "Kopf" (=> Hesse oder Pfälzer ?) ?
Man kann keine r-Strings "eingeben". r-Strings sind einzig und alleine eine Sache des Python Lexers, der deinen Quellcode verarbeitet. Du musst auf der anderen Seite aber auch ueberhaupt nichts extra escapen, denn diese Notwendigkeit ist AUCH nur eine, die der Python-Lexer von dir verlangt. Denn der will ja aus \n ein newline machen.
ok, verstanden. Dann lese ich wohl auch noch die falschen Tuts, oder verstehe diese nicht :-(

Code: Alles auswählen

import re
rex = input("rex eingeben:")
eingabe = "..A"
print(re.match(rex, eingabe))
funktioniert zB mit Eingabe
...
..A
aber nicht
..\.
eh klar. Darum ging es mir auch nicht. Ist eigentlich "re.search" nicht 'besser' als "re.match", abgesehen von evtl. Laufzeiten oder Speicherbelegungen ?
Aber deine nächste Bemerkung kommt meiner ursprünglichen Frage (eigentlich) am nächsten:

Code: Alles auswählen

print(input("eingabe:"))
genutzt in der Shell

Code: Alles auswählen

$ python3 /tmp/test.py 
eingabe:\t
\t
Das war es ja gewesen:
Im Script funktionierte

Code: Alles auswählen

re.search(r"blablub", teststring)  ## match !
Aber nicht, wenn ich es als Variable übergeben hatte:

Code: Alles auswählen

ra = input ("Regex :")     ## Eingabe: r"blablub"
print(ra)                  ## Ausgabe: r"blablub"
re.search(ra, teststring)  ## no matching !
das habe ich eben noch nicht verstanden. Es ist also nicht das Ding, WO etwas geparst wird, sondern VON WEM, richtig?
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
vielen lieben Dank :-)
auch ganz nett, oder ?

Code: Alles auswählen

.
.
.
            else:
                if match:
                    print()
                    print(match.group(0))
                    print("*" * len(match.group(0)))
                    break
.
.
.
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Nee, ich habe mich nicht vertippt. Um *einen* Backslash zu matchen muss man zwei angeben, denn der Backslash hat in regulären Ausdrücken eine besondere Bedeutung: Damit kann man andere Zeichen mit besonderer Bedeutung in regulären Ausdrücken von eben jener besonderen Bedeutung befreien. Und damit halt auch den Backslash selbst.

Durch ``import modulname`` wird schon das gesamte Modul samt Inhalt in den Speicher geladen und ausgeführt, aber in Deinem Modul existiert danach nur `modulname` als zusätzlicher Name und nicht alles was in dem importierten Modul auf Modulebene definiert wurde. Du kannst auch mit ``from modulname import name, noch_ein_name`` explizit Werte aus dem Modul unter den angegebenen Namen in Dein Modul holen.

Der Unterschied zwischen `re.search()` und `re.match()` ist das in letzterem ein implizites '^' am Anfang des regulären Ausdrucks angenommen wird. Da ist also weniger eine Frage was besser ist, sondern was man braucht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
danke für deine Antwort UND Geduld !
Nee, ich habe mich nicht vertippt. Um *einen* Backslash zu matchen muss man zwei angeben, denn der Backslash hat in regulären Ausdrücken eine besondere Bedeutung: Damit kann man andere Zeichen mit besonderer Bedeutung in regulären Ausdrücken von eben jener besonderen Bedeutung befreien. Und damit halt auch den Backslash selbst.
ich glaube, jetzt reden wir aneinander vorbei. Klar, dass ein Backslash eine Escape-Funktion hat, kein Thema. Und wenn man ihn expliziet alleine matchen will, dass man ihn ebenfalls maskieren muß (*zwei* \). Ebenso beispielsweise bei *einem*. => \.
Mir ging es um deinen zweiten Satz:
Um *einen* \ zu matchen (=> vertippt?) muss die Zeichenkette im Python-Quelltext entweder so aussehen: r'\\' oder aber ohne das r so: '\\\\'. Beide Zeichenketten enthalten genau zwei \.
warum *vier* \ ? Damit matcht man doch *zwei* \, oder ?
Durch ``import modulname`` wird schon das gesamte Modul samt Inhalt in den Speicher geladen und ausgeführt, aber in Deinem Modul existiert danach nur `modulname` als zusätzlicher Name und nicht alles was in dem importierten Modul auf Modulebene definiert wurde.
... weil ich es dann mit '[modulname].[Funktion/Methode]' ansprechen kann ...

Code: Alles auswählen

>>> import math
>>> zahl = 25
>>> math.sqrt(zahl)
5.0
>>> 
Du kannst auch mit ``from modulname import name, noch_ein_name`` explizit Werte aus dem Modul unter den angegebenen Namen in Dein Modul holen.
ja, klar. Ansprechen dann mit [Funktionsname/Methodenname] ...

Code: Alles auswählen

>>> from math import sqrt
>>> zahl = 25
>>> sqrt(zahl)
5.0
verstehe: der Namensraum! Namenkollision! (bei from [modulname] import *) ...
Der Unterschied zwischen `re.search()` und `re.match()` ist das in letzterem ein implizites '^' am Anfang des regulären Ausdrucks angenommen wird. Da ist also weniger eine Frage was besser ist, sondern was man braucht.
Verstehe. 're.match()' wäre dann die Frage/Intension nach einem Vorkommen am Anfang eines Teststrings und bei 're.search()' wäre die Frage/Intension nach einem generellen Vorkommen im Teststring. Und 're.findall()' sucht nach allen Vorkommen im Teststring ...
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Vier \ in '\\\\' sind wie ich ja gezeigt habe *zwei* \ die dann tatsächlich in der Zeichenkette stehen. Noch mal:

Code: Alles auswählen

In [57]: len('\\\\')
Out[57]: 2

In [58]: print('\\\\')
\\
Denn in Python hat der \ in Zeichenkettenliteralen ja ebenfalls eine besondere Bedeutung und um *einen* \ zu haben muss man *zwei* schreiben. Oder eben durch das r die besondere Bedeutung des \ in einem ”rohen” Zeichenkettenliteral aufheben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
ich will nicht klugsch..., das steht mir als Anfänger auch nicht zu. Ich wollte dich nur auf einen Tippfehler aufmerksam machen ...
Um *einen* \ zu matchen (=> vertippt?) muss die Zeichenkette im Python-Quelltext entweder so aussehen: r'\\' oder aber ohne das r so: '\\\\'. Beide Zeichenketten enthalten genau zwei \.
richtig wäre doch :
Um *zwei* \ zu matchen muss die Zeichenkette im Python-Quelltext entweder so aussehen: r'\\' oder aber ohne das r so: '\\\\'. Beide Zeichenketten enthalten genau zwei \.
.. das hatte mich anfangs verwirrt.
Und abermals einen großen Dank für die schnelle Antwort und für deine Geduld.
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Nein, das ist kein Tippfehler. Um *einen* \ zu matchen braucht man ein Muster das aus *zwei* \ besteht, also r'\\' oder '\\\\', weil der \ auch in regulären Ausdrücken eine besondere Bedeutung hat. Einer einzeln ist ein Syntaxfehler:

Code: Alles auswählen

In [59]: re.compile('\\')
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-59-767e3fe860e6> in <module>()
----> 1 re.compile('\\')

/usr/lib/python3.6/re.py in compile(pattern, flags)
    231 def compile(pattern, flags=0):
    232     "Compile a regular expression pattern, returning a pattern object."
--> 233     return _compile(pattern, flags)
    234 
    235 def purge():

/usr/lib/python3.6/re.py in _compile(pattern, flags)
    299     if not sre_compile.isstring(pattern):
    300         raise TypeError("first argument must be string or compiled pattern")                                                                            
--> 301     p = sre_compile.compile(pattern, flags)
    302     if not (flags & DEBUG):
    303         if len(_cache) >= _MAXCACHE:

/usr/lib/python3.6/sre_compile.py in compile(p, flags)
    560     if isstring(p):
    561         pattern = p
--> 562         p = sre_parse.parse(p, flags)
    563     else:
    564         pattern = None

/usr/lib/python3.6/sre_parse.py in parse(str, flags, pattern)
    845     # parse 're' pattern into list of (opcode, argument) tuples
    846 
--> 847     source = Tokenizer(str)
    848 
    849     if pattern is None:

/usr/lib/python3.6/sre_parse.py in __init__(self, string)
    229         self.index = 0
    230         self.next = None
--> 231         self.__next()
    232     def __next(self):
    233         index = self.index

/usr/lib/python3.6/sre_parse.py in __next(self)
    243             except IndexError:
    244                 raise error("bad escape (end of pattern)",
--> 245                             self.string, len(self.string) - 1) from None
    246         self.index = index + 1
    247         self.next = char

error: bad escape (end of pattern) at position 0
Man braucht *zwei*:

Code: Alles auswählen

In [60]: regex = re.compile('\\\\')

In [61]: regex.pattern
Out[61]: '\\\\'

In [62]: len(regex.pattern)
Out[62]: 2

In [63]: print(regex.pattern)
\\
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
vielleicht ist es bereits zu spät, vielleicht bin ich einfach auch nur zu dumm. Momentan will's einfach nicht in meine Birne.
Wenn ich einen Teststring "67\78" habe und somit nach *einem* \ suche, dann gebe ich als regex (input) "\\" ein und es gibt einen Treffer (siehe unser Script) ...
wenn ich nach einer windows-spezifischen Pfadangabe suche "c:\blablub", dann muß ich *vier* \ nehmen, da der Pfad in Python "c:\\blablub" heißt, weil der *eine* \ durch einen *zweiten*\ maskiert werden muß ... komm, laß gut sein ...
Vielen Dank für deine kostbare Zeit, die du für mich geopfert hast. Vielleicht wird's mit Beispielen einfacher ...
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich habe doch jedes mal Beispiele geliefert. Und Du schreibst jetzt doch selbst das Du wenn Du nach *einem* \ suchst, im regulären Ausdruck *zwei* \ benötigst.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
ich kenne leider nicht alle Methoden/Funktionen, die du in deinen Beispielen aufgeführt hast, muß ich erst mal nachlesen ...
ja, wenn ich *einen* \ suche, dann *zwei*\ in regex, das ist klar, aber eben nicht *vier* \ !
*vier* \ in regex, wenn ich *zwei* suche ...

diese Aussage von dir (auf's Wesentliche gekürzt) verwirrt mich eben:
Um *einen* \ zu matchen [...] so: '\\\\' [...]
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Um einen \ zu matchen braucht der reguläre Ausdruck zwei \ und um zwei \ in einem normalen Zeichenkettenliteral in Python zu schreiben braucht man vier \. Man muss den einen \ einmal für den regulären Ausdruck escapen, und dann die beiden noch mal für den Python-Compiler, macht insgesamt vier. Weil, und hier wiederhole ich mich jetzt nochmal: '\\\\' ist ein Zeichenkettenliteral das eine Zeichenkette mit *zwei* \ beschreibt:

Code: Alles auswählen

In [83]: len('\\\\')
Out[83]: 2

In [84]: print('\\\\')
\\
Und jetzt sag bitte nicht das Du `len()` und `print()` nicht kennst.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
ja, nee, len() und print() kenne ich bereits ;-)
das Prinzip ist generell klar :
die doppelte Anzahl des zu matchenden Strings in der regex, kein Thema, war mir immer klar.
Der Hase liegt woanders begraben (das war auch die ganze Zeit das Mistverständnis; dass ich nie den Compiler in Betracht gezogen habe, was jedoch für dich selbstverständlich war.) :
warum muß ich das nochmals für den Compiler doppeln (also dann insgesamt zweimal doppeln) ?
ich habe doch den Teststring (mit *einem* \) und meine regex (mit *zwei* \). Findet doch das Match durch 're.search()' und gut ist. Warum muß ich also nochmals für den Compiler die regex maskieren (=> *vier* \) ?
Wo liegt mein Denkfehler ?
Unser Script liefert doch ab !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Antworten