Ich habe folgendes in einer txt-Datei:
<ol><li><b><a href="/page1/Mark_Yato" title="Mark Yato">Mark Yato</a> ft. MarkAm & <a href="/page1/Giv%C4%93on" title="Givēon">Givēon</a> - <a href="/page1/Mark_Yato:Thuieo" title="Mark Yato:Thuieo">Thuieo</a> (7)</b></li>
<li><b><a href="/page1/The_Central" title="The Central">The Central</a> - <a href="/page1/The_Central:AHTIOe oie" title="The Central:AHTIOe oie">AHTIOe oie</a> (7)</b></li>
<li><b><a href="/page1/Taa_Too_A" title="Taa Too A">Taa Too A</a> - <a href="/page1/Taa_Too_A:ryhwtyw w" title="Taa Too A:ryhwtyw w">ryhwtyw w</a> (8)</b></li>
und versuche, es wie folgt auszugeben:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
Um dies zu erreichen, dachte ich, ich würde versuchen, „<“, „>“ und alles dazwischen zu entfernen, sodass nur die Liste übrig bleibt, die ich abrufen möchte.
Ich habe bereits den folgenden Sed-Befehl ausprobiert:
sed 's/<[^()]*>//g'
aber dies gibt nur Folgendes aus:
(7)
(7)
(8)
Was mache ich falsch und wie kann ich den Sed-Befehl reparieren oder in awk übersetzen, wenn er dafür besser geeignet ist?
Antwort1
Das Parsen von Markup mit regulären Ausdrücken istnotorisch problematisch.
Obwohl dies bei Ihren Beispieldaten kein Problem darstellt, können spitze Klammern in Tag-Attributen, Kommentaren und möglicherweise an anderen Stellen erscheinen, wodurch reguläre Ausdrücke, die von <
bis übereinstimmen, >
unzuverlässig werden.
Sie sollten auf Tools zurückgreifen, die einen Markup-Parser implementieren.
Verwenden Sie beispielsweisepandoc(Version >= 2.8) mit Ihren Beispieldaten (ohne das fehlende </ol>
Tag hinzuzufügen):
$ pandoc -f html -t plain file
Mark Yato ft. MarkAm & Givēon - Thuieo (7)
The Central - AHTIOe oie (7)
Taa Too A - ryhwtyw w (8)
Sie können diese Ausgabe dann problemlos als normalen Text nachbearbeiten, um Leerzeilen und andere unerwünschte Teile zu entfernen:
$ pandoc -f html -t plain file |
sed -e '/^$/d' -e 's/[[:blank:]]*([[:digit:]]*)$//'
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
Beachten Sie, dass vor Version 2.8 pandoc
jeder hervorgehobene Text in Großbuchstaben umgewandelt wurde, wenn die Ausgabe im plain
Format generiert wurde. Das <b>
Tag in Ihren Listenelementen löste dieses Verhalten aus (mehr dazu imÄnderungsprotokolloder die entsprechendenbegehenauf GitHub).
Abhängig von Ihren tatsächlichen Eingabedaten könnte eine Problemumgehung darin bestehen, markdown
das pandoc
Eingabeformat von entweder explizit zu verwenden:
pandoc -f markdown -t plain file
oder implizit, wenn man bedenkt, dass dies die pandoc
automatische Standardeinstellung ( pandoc -t plain file
) ist.
Antwort2
Sie sind fast am Ziel – Regex-Übereinstimmungen sind „gierig“, daher müssen Sie dem Muster mitteilen, dass das schließende >
Zeichen innerhalb des Musters nicht zulässig ist. Anders ausgedrückt: Der [^()]*
Teil innerhalb des Musters wird „gierig“ mit so viel Text übereinstimmen, wie möglich. Wenn Sie dem Muster nicht mitteilen, das schließende Zeichen >
aus diesem Teil des Musters auszuschließen, sind die vom Regex verwendeten öffnenden <
und schließenden Zeichen >
nicht unbedingt diejenigen, die aus HTML-Sicht gepaart sind.
Verwenden Sie stattdessen Folgendes:
sed -e 's/<[^>]*>//g'
Dies zwingt den regulären Ausdruck, jedes HTML-Tag zu löschen, nicht einen größeren Textblock, der am Ende sowie <
in der Mitte „ und“ hat.>
<
>
Antwort3
Sie können php
alle HTML-Tags entfernen und die HTML-Entitäten wieder in normale Zeichen umwandeln:
$ <file php -r 'echo htmlspecialchars_decode(strip_tags(file_get_contents("php://stdin")), ENT_HTML5);'
Mark Yato ft. MarkAm & Givēon - Thuieo (7)
The Central - AHTIOe oie (7)
Taa Too A - ryhwtyw w (8)
Um zusätzlich Leerzeichen (Leerzeichen, Tabulatoren) zu entfernen, auf die ein öffnendes (
, gefolgt von einer oder mehreren Zahlen und einem schließenden Zeichen )
an den mit endenden Zeilen folgt sed
:
$ <file php -r 'echo htmlspecialchars_decode(strip_tags(file_get_contents("php://stdin")), ENT_HTML5);' |
sed 's/[[:blank:]]*([[:digit:]][[:digit:]]*)$//'
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
Antwort4
Verwendung von xmlstarlet
:
xmlstarlet fo -H file |
xmlstarlet sel -E latin1 -t -v '//li' -nl 2>/dev/null |
xmlstarlet unesc | sed 's/ [^ ]*$//'
Dies dient xmlstarlet
dazu, das HTML-Fragment in ein wohlgeformtes HTML-Dokument umzuwandeln (der 1. Befehl). Anschließend extrahiert es den Wert jedes li
Knotens (der 2. Befehl). Schließlich dekodiert es alle HTML-Entitäten ( &
zum Beispiel). Der letzte sed
Befehl löscht einfach alles nach dem letzten Leerzeichen in jeder Zeile (es gibt Zahlen in Klammern, die nicht Teil der Ausgabe sein sollten).
Die Ausgabe des in der Frage enthaltenen Dokuments:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w