Holen Sie sich die URL aus HTML@lala hereingefragt Wie kann die Regex-Ersetzung <*> verwendet werden? über das Greifen URLs aus HTML . Hier sind ein wenig mehr Details zu drei vorgeschlagenen Antworten. Zunächst der Haftungsausschluss: Keines dieser Beispiele kann HTML richtig analysieren, sodass alle URLs finden können, die nicht wirklich vorhanden sind, und andere URLs übersehen, die wirklich vorhanden sind.
/*
THIS IS NOT AN HTML PARSER
HTML parsers are hard to write. There are better ways.
Neither of these JSL ideas can properly skip comments or
many other HTML tags that should be skipped. They will
find things they shouldn't and miss other things they
should find. They've only been minimally tested on one site.
This code is presented as "how can I use contains() vs patmatch()
to efficiently work through a large string looking for something?"
The second example is FIVE TIMES FASTER and a LITTLE MORE ACCURATE.
The third example uses text explorer to grab links. I don't think
there is a pre-existing regex for the link text descriptions. It works
very similar to this code; it is NOT an HTML parser either.
If you can use python, you might want to investigate "beautiful soup".
I've not used it, but believe it addresses the "hard to write" issue.
*/
Die Probleme beim Analysieren von HTML bestehen hauptsächlich darin, übereinstimmende Start- und End-Tags zu finden und die Daten zwischen ihnen zu betrachten. Alle hier vorgestellten JSL können durch HTML-Features ausgehebelt werden. Aber es könnte gut genug sein; machen Sie Ihre eigenen Tests. Siehe auch Schöne Suppe was vielleicht eine bessere Antwort wäre.
Hier ist ein Ausschnitt aus einer HTML-Webseite, der einen Link (das -Tag) mit einer URL (dem Teil href=) und etwas Text (dem Teil Diskussionen) zeigt, der auf der Seite sichtbar sein wird.
< a > tag with URL and Text< a > Tag mit URL und Text
Das Ziel ist es, eine Datentabelle der URLs und des Linktextes zu erstellen, eine pro Zeile. Eine typische Webseite kann etwa 100 Links haben und ein halbes Megabyte Text umfassen. Einer langsam Eine Möglichkeit, das Problem anzugehen (nicht gezeigt), besteht darin, eine einfache Regex zu schreiben, die einen Link nach dem anderen findet, den Link aus dem Text zu entfernen und dies zu wiederholen, bis kein weiterer gefunden werden kann. Wenn es nur ein oder zwei sind, großartig. Aber wenn es 100er sein könnten, dann werden einige hundert Megabyte an Daten manipuliert und durchsucht.
Ein schnellerer Weg besteht darin, die Daten zu durchsuchen, sich immer vorwärts zu bewegen und die Datentabelle zu erstellen, wenn Links gefunden werden. Das erste Beispiel verwendet die Funktion contains(), die ein drittes Argument hat, um eine Startposition anzugeben. Contains() gibt auch eine gefundene Position zurück. Indem die Startposition direkt hinter der gefundenen Position aktualisiert wird, kann contains() den Text effizient durchsuchen, ohne den Text sichern oder ändern zu müssen.
u = "https://community.jmp.com/t5/Discussions/bd-p/discussions";
txt = Load Text File( u );
// a link on a page has at least two parts:
// the URL and some descriptive text.
// <A ...="" href="https://community.jmp.com/url" ...="" target="_blank" rel="nofollow noopener noreferrer"> descripton </A>
// p1 p4 p5
// using contains and regex. "<A>", p1 + 3 ); // find the end of the opening tag
p5 = Contains( txt, "</A>", p4 + 1 ); // find the ending tag
if( p5 > p4, // as long as the end is not zero, we found one, see break() below
desc = Substr( txt, p4 + 1, p5 - p4 - 1 ); // the visible link description. Images can be here too.
desc = Regex( desc, "<[^>]*>", "", globalreplace ); // remove span, image, etc tags
linktext = Substr( txt, p1, p4 - p1 + 1 ); // <A href="https://community.jmp.com/" target="_blank">
hreftext = Regex( linktext, "href\s*=\s*(\!"|')(.*?)(\1)", "\2" );// use regex to get the href value
if( !Is Missing( hreftext ), // sometimes there isn't one
dt << addrows( 1 );
irow = N Rows( dt );
dt:link[irow] = hreftext;
dt:description[irow] = desc;
);
, // else
Break() // no more end tags. there is maybe a mess of javascript.
);
pos = Max( pos, p5 + 3 ); // advance past the one just found
);
stoptime = Tick Seconds();
dt << endDataUpdate;
Show( stoptime - starttime ); </A>
Das Herzstück dieses Codes ist die Zeile
while( (p1 = Contains( txt, "<A></A>
was eine Reihe von Aufgaben erledigt: Es verwendet pos im 3. Argument, um vorherige Arbeiten zu überspringen, es findet das nächste Nichts gefunden , also stoppt die Schleife. Die nächste Zeile
p4 = Contains( txt, ">", p1 + 3 );
sucht nach dem übereinstimmenden >, das das p5 = Contains( txt, "", p4 + 1 );
p5 zeigt auf das -Tag, das den Linktext beendet. Viele, aber nicht alle HTML-Tags funktionieren so, ein Start-Tag ohne den / und ein End-Tag mit dem Schrägstrich. Manchmal sind Start- und End-Tag identisch, wobei verwendet wird, aber diese JSL ignoriert diese Möglichkeit.
Die if-Anweisung bestimmt, ob etwas gefunden wurde, und nimmt die Beschreibung wie folgt auf
desc = Substr( txt, p4 + 1, p5 - p4 - 1 );
p4 und p5 zeigen auf > und <. p4+1 ist also das erste Beschreibungszeichen und p5-p4-1 ist die Länge der Beschreibung. Die nächste Zeile bereinigt die Beschreibung, indem eingebettete Tags entfernt werden
desc = Regex( desc, "<[^>]*>", "", globalreplace );
GlobalReplace bedeutet, dass die Regex das Muster findet und diesen Text so oft wie möglich durch nichts ersetzt. Das Muster entspricht <, gefolgt von null oder mehr Zeichen, die keine > sind, gefolgt von >, das ein 
-Tag oder eine Reihe von Textstil-Tags sein kann. Das Endergebnis ist der Text des Tags ohne Bild/Farbe/Schriftart/usw.
Die nächsten beiden Zeilen sind ähnlich, um eher die URL als die Beschreibung zu erfassen
linktext = Substr( txt, p1, p4 - p1 + 1 ); // <A href="https://community.jmp.com/" target="_blank">
hreftext = Regex( linktext, "href\s*=\s*(\!"|')(.*?)(\1)", "\2" );// use regex to get the href value</A>
p1 und p4 (siehe Kommentar) sind die gesamten Link-Tag-Positionen; Linktext ist das Link-Tag mit einer Reihe unerwünschter Bits. Der hreftext verwendet regex(), um nur die URL zwischen den href-Anführungszeichen oder Apostrophen zu extrahieren. Das Regex-Muster verwendet den Backref \1, um sicherzustellen, dass das abschließende Apostroph oder Anführungszeichen mit dem führenden übereinstimmt. Der erste offene Paren im Regex-Muster erstellt eine Erfassungsgruppe (für \1), die mit " oder ' übereinstimmt. Der zweite offene Elternteil ist eine Erfassungsgruppe (für \2), die übereinstimmt und sich widerwillig so weit vorwärts bewegt, wie es für die Übereinstimmung zwischen den Trennzeichen erforderlich ist. Der dritte offene Elternteil ist Erfassungsgruppe 3; die Klammern und die Gruppierung werden nicht wirklich benötigt. Das Ergebnis, \2, ist nur die URL.
Alles andere als fertig: Wenn es eine Beschreibung gibt, fügen Sie eine Zeile zur Tabelle hinzu und rücken Sie dann, ganz wichtig, die pos-Variable vor!
pos = Max( pos, p5 + 3 );
Max passt auf, dass es am Ende nicht rückwärts geht und in einer Schleife hängen bleibt.
Ein schneller Weg
Der obige Code ist ziemlich schnell, aber das ist noch besser.
u = "https://community.jmp.com/t5/Discussions/bd-p/discussions";
txt = Load Text File( u );
// using pattern matching and regex
// this is about 5X faster and skips over the garbage in the <SCRIPT> sections
// two patterns, one for &amp;amp;amp;lt;a&amp;amp;amp;gt; links and one for &amp;amp;amp;lt;script&amp;amp;amp;gt; to skip over
linkpat = "&amp;amp;amp;lt;a " + Pat Break( "&amp;amp;amp;gt;" ) &amp;amp;amp;gt;&amp;amp;amp;gt; linktext + "&amp;amp;amp;gt;" + Pat Arb() &amp;amp;amp;gt;&amp;amp;amp;gt; desctext + "&amp;amp;amp;lt;/a&amp;amp;amp;gt;";
scriptpat = "&amp;amp;amp;lt;script" + Pat Break( "&amp;amp;amp;gt;" ) + "&amp;amp;amp;gt;" + Pat Arb() + "</SCRIPT>";
dt = New Table( "patmatch", New Column( "description", Character, "Nominal" ), New Column( "link", Character, "Nominal" ) );
Wait( .1 );
dt << beginDataUpdate;
startTime = Tick Seconds();
rc = patmatch( txt,
patrepeat( // repeat the pattern until no more
(linkpat + pattest(// run some JSL for the linkpat...
desc = Regex( desctext, "<[^>]*>", "", globalreplace ); // remove span, etc tags
hreftext = Regex( linktext, "href\s*=\s*(\!"|')(.*?)(\1)", "\2" );
if( !Is Missing( hreftext ),
dt << addrows( 1 );
irow = N Rows( dt );
dt:link[irow] = hreftext;
dt:description[irow] = desc;
);
1; // pattest needs this to succeed
)) | scriptpat /* maybe skip a script */ | /* maybe skip to the next tag */ (Pat Len( 1 ) + Pat Break( "<" ))
),
NULL,IGNORECASE
);
stoptime = Tick Seconds();
dt << endDataUpdate;
Show( stoptime - starttime );
Show( rc ); // should be 1, not 0Diesmal befindet sich die Schleife innerhalb des Musterabgleichers (unter Verwendung von patrepeat(), um das Muster durch den String zu schieben). Die zwei Muster
linkpat = "<A>" ) >> linktext + ">" + Pat Arb() >> desctext + "</A>";
scriptpat = "<SCRIPT>" ) + "&amp;amp;amp;gt;" + Pat Arb() + "</SCRIPT>";
erledigen zwei verschiedene Aufgaben: linkpat vergleicht Text und speichert Teile der Übereinstimmung in linktext und desctext. Scriptpat vergleicht Text zwischen und ignoriert ihn. Das -Tag in HTML definiert einen JavaScript-Codeabschnitt, der ignoriert werden sollte. In diesem Beispielfall enthält das JavaScript viele &amp;amp;amp;lt;a-Sequenzen, die falsch positive Ergebnisse liefern, und das Überspringen des JavaScripts eliminiert sie. Mehr dazu gleich. Die Schleife wird nun durch das beginnende patmatch() durchgeführt&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;PRE&amp;amp;amp;gt;&amp;amp;amp;lt;CODE class=" language-jsl"&amp;amp;amp;gt;rc = patmatch( txt,&amp;amp;amp;lt;/CODE&amp;amp;amp;gt;&amp;amp;amp;lt;/PRE&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Am Ende überprüft show(rc), dass das Patmatch erfolgreich war. Aber zuerst, das zweite Argument für patmatch ist das Muster&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;PRE&amp;amp;amp;gt;&amp;amp;amp;lt;CODE class=" language-jsl"&amp;amp;amp;gt; patrepeat( // repeat the pattern until no more
(linkpat + pattest(// run some JSL for the linkpat...
desc = Regex( desctext, "&amp;amp;amp;lt;[^&amp;amp;amp;gt;]*&amp;amp;amp;gt;", "", globalreplace ); // remove span, etc tags
hreftext = Regex( linktext, "href\s*=\s*(\!"|')(.*?)(\1)", "\2" );//
if( !Is Missing( hreftext ), //
dt &amp;amp;amp;lt;&amp;amp;amp;lt; addrows( 1 );//
irow = N Rows( dt );//
dt:link[irow] = hreftext;//
dt:description[irow] = desc; //
);//
1; // pattest needs this to succeed
)) | scriptpat /* maybe skip a script */ | /* maybe skip to the next tag */ (Pat Len( 1 ) + Pat Break( "&amp;amp;amp;lt;" ))
),&amp;amp;amp;lt;/CODE&amp;amp;amp;gt;&amp;amp;amp;lt;/PRE&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;die in drei Teile vereinfacht werden kann&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;PRE&amp;amp;amp;gt;&amp;amp;amp;lt;CODE class=" language-jsl"&amp;amp;amp;gt;patrepeat(
linkpat // part 1
|
scriptpat // part 2
|
(Pat Len( 1 ) + Pat Break( "&amp;amp;amp;lt;" )) // part 3
)&amp;amp;amp;lt;/CODE&amp;amp;amp;gt;&amp;amp;amp;lt;/PRE&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Das bedeutet, dass bei jedem Schritt auf dem Weg eines dieser drei Muster mit einem Text übereinstimmt. Sehen Sie zuerst, ob das Linkpat übereinstimmt; das wird einen Teil der Arbeit erledigen, die vereinfacht wurde. Wenn nicht, prüfen Sie, ob das scriptpat übereinstimmt; das wird etwas JavaScript überspringen. Überspringen Sie andernfalls ein Zeichen (normalerweise ein &amp;amp;amp;lt;) plus genügend Zeichen, um das nächste &amp;amp;amp;lt; zu erreichen. Schleife dann für mehr.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Der Teil, der vereinfacht wurde, ist die JSL, die ausgeführt wird, wenn der Linkpat erfolgreich ist (denken Sie daran, dass Linkpat etwas Text in Linktext und Desctext speichert, wenn er mit ihnen übereinstimmt).&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;PRE&amp;amp;amp;gt;&amp;amp;amp;lt;CODE class=" language-jsl"&amp;amp;amp;gt;linkpat + pattest(
desc = Regex( desctext, "&amp;amp;amp;lt;[^&amp;amp;amp;gt;]*&amp;amp;amp;gt;", "", globalreplace );
hreftext = Regex( linktext, "href\s*=\s*(\!"|')(.*?)(\1)", "\2" );
if( !Is Missing( hreftext ),
dt &amp;amp;amp;lt;&amp;amp;amp;lt; addrows( 1 );
irow = N Rows( dt );
dt:link[irow] = hreftext;
dt:description[irow] = desc;
);
1; // pattest needs this to succeed
)&amp;amp;amp;lt;/CODE&amp;amp;amp;gt;&amp;amp;amp;lt;/PRE&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Das sollte sehr ähnlich aussehen wie die JSL im ersten Beispiel, die Zeilen in die Datentabelle schreibt. pattest() ist eine spezielle Mustervergleichsfunktion, die 1 zurückgibt, wenn der Vergleich erfolgreich sein sollte, und 0, wenn er fehlschlagen sollte. Hier wird pattest verwendet, um etwas JSL auszuführen, und gibt immer 1 zurück, damit der Matcher vorwärts gehen kann. Das JSL, das es ausführt, ist es nicht wirklich&amp;amp;amp;lt;EM&amp;amp;amp;gt; testen&amp;amp;amp;lt;/EM&amp;amp;amp;gt; wenn der Matcher sichern und es erneut versuchen muss; die JSL aktualisiert nur die Tabelle.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Ich glaube, dass dies schneller ist als das vorherige Beispiel, da das vorherige Beispiel contains() mit einer Startposition aufruft und dafür noch etwas Vorbereitungszeit hat. Hier gibt es einen einzigen Aufruf von patmatch mit nur einem einzigen Setup-Overhead.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Beide Beispiele verwenden Regex für kleinere Aufgaben innerhalb des Gesamtbildes: das Extrahieren des Linktexts und der URL aus einer kurzen Zeichenfolge.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;&amp;amp;amp;nbsp;&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;In der Antwort ist Text Explorer auch eine mögliche Lösung. Es verfügt über eine Bibliothek mit vorgefertigten regulären Ausdrücken, die einen Link-Grabber enthalten, aber keinen beschreibenden Text-Grabber. In einigen Fällen ist es möglicherweise einfacher, aber wahrscheinlich nicht schneller.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;&amp;amp;amp;nbsp;&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;/lingo-body&amp;amp;amp;gt;&amp;amp;amp;lt;lingo-teaser id="lingo-teaser-367121" slang="en-US"&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;&amp;amp;amp;lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Clickable URL in a &amp;amp;amp;lt; a &amp;amp;amp;gt; link tag" style="width: 456px;"&amp;amp;amp;gt;&amp;amp;amp;lt;img src="https://us.v-cdn.net/6038925/uploads/images/31168i4AA911021B7FAF36/LinkWithTextAndURL.png" role="button" title="LinkWithTextAndURL.png" alt="Anklickbare URL in einem Link-Tag &amp;amp;amp;lt; a &amp;amp;amp;gt;" /&amp;amp;amp;gt;&amp;amp;amp;lt;span class="lia-inline-image-caption" onclick="event.preventDefault();"&amp;amp;amp;gt;Anklickbare URL in einem Link-Tag &amp;amp;amp;lt; a &amp;amp;amp;gt;&amp;amp;amp;lt;/span&amp;amp;amp;gt;&amp;amp;amp;lt;/span&amp;amp;amp;gt;&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Verwenden Sie Regex oder Text Explorer&amp;amp;amp;lt;SPAN style="font-family: inherit;"&amp;amp;amp;gt; um URLs in HTML zu finden&amp;amp;amp;lt;/SPAN&amp;amp;amp;gt;&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;/lingo-teaser&amp;amp;amp;gt;