Character in String, and-Kette, Verwirrung

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.
Antworten
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

Hallo.

Ich komme direkt zum Thema:

Code: Alles auswählen

def test():
    string = "asdad.asdasd"
    if "@" and "." not in string:
        return False
    else:
        return True

print(test())
Warum bekomme ich hier "True"?

Ist der "and" Operator falsch genutzt? Ich möchte eine Email Adresse validieren. Sprich es muss ein "@" Zeichen und ein Punkt im String enthalten sein.

Ich danke im Voraus!
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

`and` funktioniert nicht so wie Du denkst. `and` gibt den linken Ausdruck zurück wenn er sich zu False evaluiert, sonst den rechten. Bei Dir ist "@" immer wahr, somit wird immer der rechte Ausdruck genommen, und "." kommt in string vor, also wird der if-Block ausgeführt.

Du brauchst also links auch einen String-Test:

Code: Alles auswählen

def test():
    string = "asdad.asdasd"
    return "@" in string and "." in string
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

(Ergänzend zu Sirius 3, der schneller war:)

Ja, der and Operator ist hier falsch verwendet. Du prüfst ob '@' existiert (was wahr ist) und einmal, ob '.' nicht in 'string' enthalten ist (was falsch ist); True und False ist False, also wird der Else-Teil ausgeführt. 'if "@" in string and "." in string: …', prüft, ob beide enthalten sind.

(Übrigens: Für den produktiven Einsatz würde man eine E-Mail-Adresse nicht so so validieren. Da nimmt man zumindest einen regulären Ausdruck.)
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Anscheinend ist es recht schwer, E-Mailadressen richtig zu validieren. Ich würde also nur auf `"@" in string` testen und dann versuchen, die Adresse zu verwenden.
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

nezzcarth hat geschrieben: Samstag 9. Juni 2018, 13:59 (Übrigens: Für den produktiven Einsatz würde man eine E-Mail-Adresse nicht so so validieren. Da nimmt man zumindest einen regulären Ausdruck.)
Da mit der o.g. Bedingung ja auch eine E-Mail-Adressen wie ".test@example.com" valide ist. Ebenso, ob bestimmte Sonderzeichen zusätzlich vorkommen, oder die länge des local part überschritten wurde.
When we say computer, we mean the electronic computer.
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

narpfel hat geschrieben: Samstag 9. Juni 2018, 14:09 Ich würde also nur auf `"@" in string` testen und dann versuchen, die Adresse zu verwenden.
Das kann man im Prinzip machen, man sollte aber zumindest vorher kurz überlegen, welche Eingaben denkbar und möglich sind und welche Nebeneffekte auftreten können, wenn beispielsweise eine URL "durchrutscht". Zum Beispiel würde eine valide (wenn auch seltene) URL der Form "http://user:password@python-forum.de" den Test bestehen.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Nicht zu verwechseln mit "http://user:password"@python-forum.de, was eine gültige E-Mail-Adresse wäre. :-)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Oder `(http://user:)passwort@python-forum.de(auch•gültig)`.

Die Mailadressvalidierung hier im Forum scheint mit korrekt gequoteten Adressen auch Probleme zu haben. "http://user:password"@python-forum.de ist jedenfalls nicht als `mailto:`-Link anklickbar.
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

Das mit der Validierung ist nicht so wichtig. Es ist für meinen Email Client und soll eher vertippern Einhalt gebieten.

Die von Sirius3 gepostete Lösung gefällt mir sehr gut und funktioniert auch einwandfrei.

Code: Alles auswählen

return "@" in string and "." in string
Aber wie löse ich dies wenn ich dies in einer if clause benötige? Ich habe eine Funktion die alle Felder durchcheck (also To, CC, BCC, etc...). Dabei kann ich ja nicht mehrere return haben.

Ich bräuchte so etwas in der Richtung:

if not string.contains("@", "."):
<code-für-gtk-message-dialog>
Zuletzt geändert von SnakeBite am Samstag 9. Juni 2018, 19:07, insgesamt 1-mal geändert.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Code: Alles auswählen

all(char in string for char in '@.')
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Naja, aber `root@localhost` ist auch eine gültige E-Mail-Adresse, und die würdest Du abweisen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

Snafu, genau das war es.

Das all() keyword kannte ich noch gar nicht. Wieder was gelernt!

Vielen Dank!!
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

__blackjack__ hat geschrieben: Samstag 9. Juni 2018, 19:09 Naja, aber `root@localhost` ist auch eine gültige E-Mail-Adresse, und die würdest Du abweisen.
Da hast Du zwar Recht, aber ich habe noch nie in meinem Leben eine Email an root@localhost geschickt. :-)

Es geht hier wirklich nur darum einen ganz einfachen Email client für MICH SELBST zu basteln. Sollte das mal ein Problem werden, kann man es ja relativ leicht ändern. Es ging mir auch eher darum obiges Problem zu lösen. Vielen Dank für Eure Hilfe!
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

snafu hat geschrieben: Samstag 9. Juni 2018, 19:05

Code: Alles auswählen

all(char in string for char in '@.')
OK eins drauf setzten würde ich noch gerne. Wie müsste es denn aussehen wenn ich "@" und "." drin haben will, aber beispielsweise einen "/" nicht? Ich kann das all() keyword dann ja auch nicht verwenden, weil das "and" dann ja wieder nur den rechten Teil beachtet, oder?

Das funktoniert auf jeden Fall nicht:

Code: Alles auswählen

string = "asdad.asd@as/d"
if not all(char in string for char in '@.') and all(char in string for char in "/"):
    print("ALERT")
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

SnakeBite hat geschrieben: Samstag 9. Juni 2018, 18:58Ich habe eine Funktion die alle Felder durchcheck (also To, CC, BCC, etc...). Dabei kann ich ja nicht mehrere return haben
Eine Funktion kann nur einmal »return« ausführen, aber dafür gibt es ja Funktionen, um aus einfachen Test, komplexere Dinge zusammenzubauen:

Code: Alles auswählen

def validate_email(email):
    return "@" in email and "." in email and "/" not in email
was man dann benutzen kann:

Code: Alles auswählen

if validate_email(email_to) and validate_email(email_cc) ...:
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Naja, aber irgendein anderer lokaler Rechnername als `localhost` könnte ja auch genommen werden. Der Punkt ist, das es gültige E-Mail-Adressen ohne Punkt gibt. Warum die also ohne Not ausschliessen?

`all()` ist kein Schlüsselwort sondern eine Funktion.

Das ``not`` steht an der falschen Stelle, denn Du willst ja das die beiden Zeichen darin vorkommen und nicht das beide Zeichen nicht drin vorkommen.

Nach dem ``and`` macht das `all()` keinen Sinn wenn da nur auf *ein* Zeichen geprüft wird. ``'/' not in string`` ist kürzer und macht das gleiche. Wenn es mehr werden sollten, dann braucht man da auch `any()` statt `all()`.

Aber auch hier wieder: '/' kann in gültigen E-Mails vorkommen.

Wobei in den Headern von einer E-Mail ja noch ganz andere Sachen vorkommen können.

Ausserdem würde ich sowas nicht selber schreiben — da gibt's schon Bibliotheken für.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bei nur zwei gesuchten Buchstaben würde ich wahrscheinlich auch kein all() nehmen, sondern es mit der and-Verknüpfung lösen. An sich wollte ich nur zeigen, dass es auch anders geht, wenn man mehrere Suchkriterien hat, die alle enthalten sein sollen.

Und immer schön an das Laufzeitverhalten denken: Mehrfache in-Operationen auf den gleichen Text haben quadratische Laufzeit. Jetzt ist das egal, aber bei größeren Texten kann das zum Problem werden. Wenn dann Auswirkungen auf die Laufzeit spürbar sind, sollte man sich nach Alternativen umsehen.
Antworten