Grep-Befehl - wo ist der Fehler? [gelöst!]

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
desputin
Beiträge: 1298
Registriert: 24.04.2015 17:16:34

Grep-Befehl - wo ist der Fehler? [gelöst!]

Beitrag von desputin » 28.05.2019 20:01:37

Hallo Ihr,
ich versuche mit Grep eine E-Mail-Adresse aus HTML-Code zu extrahieren.
Was mache ich falsch?

So sieht eine Quellzeile aus:

Code: Alles auswählen

<span class="u">info</span> [at] <span class="d">personx.de</span>
Der Grep-Befehl etwas unbeholfen:

Code: Alles auswählen

grep -E -o "\b[A-Za-z0-9._%+-]+[<][/][s][p][a][n][>][ ][[][a][t][]][ ][<][s][p][a][n][ ][c][l][a][s][s][=]["][d]["][>][A-Za-z0-9.-]+\.[A-Za-z]{2,6}[<][/][s][p][a][n][>]\b" Quelle.txt > Emails.txt
Viele Grüße
desputin
Zuletzt geändert von desputin am 29.05.2019 07:40:56, insgesamt 1-mal geändert.
https://www.daswirdmanjawohlnochsagenduerfen.de
https://www.neoliberalyse.de - Über die Ökonomisierung aller Lebensbereiche. |

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Grep-Befehl - wo ist der Fehler?

Beitrag von RobertDebiannutzer » 28.05.2019 21:13:52

Muss die Quellzeile erst in einer Datei gefunden werden? Existieren mehrere dieser Zeilen pro Datei? Gibt es mögliche problematische Überschneidungen? Warum ist Dein grep-Befehl so merkwürdig, hat das einen bestimmten Grund (sowas habe ich noch nie gesehen...)?
Ansonsten würde ich einfach mal sowas vorschlagen:

Code: Alles auswählen

user@host:~$ cat file
<span class="u">info</span> [at] <span class="d">personx.de</span>
user@host:~$ sed -n 's/<span class="u">\([^<]*\).*\[at\].*<span class="d">\([^<]*\).*/\1@\2/p' file
info@personx.de
Edit: Nochmal angepasst.

Benutzeravatar
desputin
Beiträge: 1298
Registriert: 24.04.2015 17:16:34

Re: Grep-Befehl - wo ist der Fehler?

Beitrag von desputin » 28.05.2019 22:05:36

Hallo Robert, vielen Dank.
zu Deinen Fragen:

-Ja, der Quelltext ist ein einer Datei
- Es existieren jeweils mehrere solcher Zeilen in der Datei, also mehrere E-Mail-Adressen. Die Syntax ist aber immer exakt gleich.
-Der Grep-Befehl ist so merkwürdig, weil ich schlecht mit regulären Ausdrücken bin :)

Danke für Deinen sed-Befehl, der funktioniert 1a!
https://www.daswirdmanjawohlnochsagenduerfen.de
https://www.neoliberalyse.de - Über die Ökonomisierung aller Lebensbereiche. |

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Grep-Befehl - wo ist der Fehler?

Beitrag von Meillo » 29.05.2019 05:54:51

Was an dem grep-Befehl seltsam war ist, dass jedes literale Zeichen in einer eigenen Zeichenklasse war. Das ist nicht noetig. Die meisten Zeichen stehen literal fuer sich selbst, so z.B. alle Buchstaben und Zahlen. Andere Zeichen kann man auch mit Backslashes escapen. Das ist ueblicher. An sich sind die Zeichenklassen aber nicht falsch, bloss etwas umstaendlich.

Sed ist insofern besser geeignet, dass man damit das Gefundene auch noch umbauen kann, was hier mit dem Ersetzen des At-Zeichens auch noetig war.

Ist die Frage damit geloest? Dann bitte im Titel so markieren.
Use ed once in a while!

Benutzeravatar
desputin
Beiträge: 1298
Registriert: 24.04.2015 17:16:34

Re: Grep-Befehl - wo ist der Fehler? [gelöst!]

Beitrag von desputin » 29.05.2019 07:41:10

Super, danke Euch beiden für die Hilfe & Erklärungen!
https://www.daswirdmanjawohlnochsagenduerfen.de
https://www.neoliberalyse.de - Über die Ökonomisierung aller Lebensbereiche. |

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Grep-Befehl - wo ist der Fehler? [gelöst!]

Beitrag von eggy » 29.05.2019 08:52:35

Code: Alles auswählen

awk -F"[<>]" '{print $3 "@" $7}' datei
Wenn man strukturierte Dateien hat, ist awk oftmals der einfachere Ansatz.

-F sagt, alle Zeichen in den eckigen Klammern werden als Feldtrenner benutzt
aus

Code: Alles auswählen

<span class="u">info</span> [at] <span class="d">personx.de</span> 
wird damit

Code: Alles auswählen

|span class="u"|info|/span| [at] |span class="d"|personx.de|/span| 
Zeile für Zeile wird in Felder zerlegt
und mit print $Zahl die gewollten Felder ausgegeben, Zählung beginnt bei 1, $0 wäre die ganze Zeile

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Grep-Befehl - wo ist der Fehler? [gelöst!]

Beitrag von Meillo » 29.05.2019 11:34:56

eggy hat geschrieben: ↑ zum Beitrag ↑
29.05.2019 08:52:35

Code: Alles auswählen

awk -F"[<>]" '{print $3 "@" $7}' datei
Nette Idee!

Robuster wird's so:

Code: Alles auswählen

awk -F"[<>]" '/> \[at\] </{print $3 "@" $7}' datei
... weil es auch noch andere Zeilen mit spitzen Klammern aber ohne Email-Adressen im Input geben koennte (sogar wahrscheinlicherweise).
Use ed once in a while!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Grep-Befehl - wo ist der Fehler? [gelöst!]

Beitrag von RobertDebiannutzer » 29.05.2019 11:46:17

Müsste man nicht auch beim awk-Befehl noch genauer die Situation spezifizieren? Ansonsten würden ja auch z.B. solche Zeilen (oder noch was ganz anders) gefunden:

Code: Alles auswählen

<br>xyz</br> [at] <br>xyz</br>
Und das ist vielleicht nicht gewollt?

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Grep-Befehl - wo ist der Fehler? [gelöst!]

Beitrag von eggy » 29.05.2019 12:02:27

@meillo: ich hatte es extra schlank gehalten, aber Du hast damit natürlich (mal wieder :evil: :mrgreen: ) Recht

meillo benutzt hier eins der supertollen Features von awk: nur dann ersetzen, wenn bestimmte Muster in der Zeile auftauchen.

Der Block in meinem Codeteil mit den geschweiften Klammern '{...}' bedeutet, dass für jede erkannte Zeile der Codeblock ausgeführt wird.

Jetzt hat awk aber noch die Möglichkeit, dass man vor die öffnende Klammer eine Bedingung schreibt und der Block dann nur ausgeführt wird, wenn diese Bedingung zutrifft.
Dafür schreibt man z.B. den gesuchten Text zwischen zwei "/", meillo hat in seinem Beispiel verlangt, die Zeile soll "> [at] <" enthalten. Damit wird nur dort ersetzt, wo dieses Muster enthalten ist. Und weil auch die Bedingungen reguläre Ausdrücke sein können, werden hier die "[" mit dem Escapezeichen "\" versehen, um awk zu sagen, dass es sich da um ein ganz normales Klammerzeichen handelt und das hier keine Charakterklasse ist.

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Grep-Befehl - wo ist der Fehler? [gelöst!]

Beitrag von Meillo » 29.05.2019 12:04:58

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
29.05.2019 11:46:17
Müsste man nicht auch beim awk-Befehl noch genauer die Situation spezifizieren? Ansonsten würden ja auch z.B. solche Zeilen (oder noch was ganz anders) gefunden:

Code: Alles auswählen

<br>xyz</br> [at] <br>xyz</br>
Und das ist vielleicht nicht gewollt?
Ja klar, man kann das beliebig weit robuster machen. Wie weit man es sinnvoll findet, muss selber entscheiden. Ich habe mich entschlossen, zumindest das ``[at]'' zu matchen, und dann dachte ich, dass es darueber hinaus noch sinnvoll waere, sicherzustellen, dass auf beiden Seiten HTML-Tags sind, weil das die zu erwartende Form (des einen einzigen Beispiels, das wir als Datenbasis haben) ist. An der Stelle war fuer mich der (auf Basis der spaerlichen Datengrundlage und meiner Erfahrung) beste Kompromiss zwischen Genauigkeit des Ausdrucks und seiner Komplexitaet.

(Man koennte auf jeder Seite noch ein ``span'' anfuegen, danach muss man aber anfangen variable Element einzubauen, was mehr Noise erzeugt und damit schlechter lesbar ist. Dass ich nicht explizit auf <span>, sondern auf ein beliebiges Tag getestet habe, ist vielleicht Folge meiner Erfahrung, dass sich ``<span class="...">'' schnell mal in ``<i>'' oder so aendert und ich davon nicht abhaengig sein wollte. Aber wie gesagt: Das ist eine Frage der eigenen Entscheidungen und der Erfahrungen, die man bislang gemacht hat.)


EDIT: @eggy: Danke fuer die tollen Erklaerungen! :THX:
Use ed once in a while!

Antworten