Prendi l'URL da HTML@lala chiesto di entrare Come è possibile utilizzare la sostituzione regex <*>? sull'afferrare URL da HTML . Ecco qualche dettaglio in più su tre risposte proposte. Innanzitutto, il disclaimer: nessuno di questi esempi esegue correttamente l'analisi dell'HTML, quindi tutti possono trovare URL che non sono realmente presenti e perdere altri URL che sono realmente presenti.
/*
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.
*/
I problemi nell'analisi dell'HTML riguardano principalmente la ricerca di tag di inizio e fine corrispondenti e l'analisi dei dati tra di loro. Tutto il JSL presentato qui può essere inciampato dalle funzionalità HTML. Ma potrebbe essere abbastanza buono; fai i tuoi test. Vedi anche Bella zuppa che potrebbe essere una risposta migliore.
Ecco uno snip da una pagina Web HTML che mostra un collegamento (il tag ) con un URL (la parte href=) e un po' di testo (la parte Discussioni) che sarà visibile sulla pagina.
< a > tag with URL and Text< a > tag con URL e testo
L'obiettivo è creare una tabella di dati degli URL e il testo del collegamento, uno per riga. Una tipica pagina web può avere circa 100 link ed essere mezzo megabyte di testo. Uno Lento il modo per affrontare il problema (non mostrato) è scrivere una semplice espressione regolare che trovi un collegamento alla volta, rimuovere il collegamento dal testo e ripetere fino a quando non se ne trovano più. Se ce ne sono solo uno o due, fantastico. Ma se ci possono essere 100, allora alcune centinaia di megabyte di dati vengono manipolati e cercati.
Un modo più veloce è cercare tra i dati, andando sempre avanti, costruendo la tabella dei dati man mano che vengono trovati i collegamenti. Il primo esempio usa la funzione contiene() che ha un terzo argomento per specificare una posizione iniziale. Contiene() restituisce anche una posizione trovata. Aggiornando la posizione iniziale appena oltre la posizione trovata, contiene() può esaminare in modo efficiente il testo senza dover eseguire il backup o modificare il testo.
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>
Il cuore di quel codice è la linea
while( (p1 = Contains( txt, "<A></A>
che sta facendo un sacco di lavori: usa pos nel 3° argomento per saltare qualsiasi lavoro precedente, trova il successivo Non abbiamo trovato nulla , quindi il ciclo si interrompe. La riga successiva
p4 = Contains( txt, ">", p1 + 3 );
cerca la corrispondenza > che termina il tag
p5 = Contains( txt, "", p4 + 1 );
p5 punterà al tag che termina il testo del collegamento. Molti, ma non tutti, i tag HTML funzionano in questo modo, un tag di inizio senza / e un tag di fine con la barra. A volte il tag di inizio e di fine è lo stesso, usando , ma questo JSL sta ignorando questa possibilità.
L'istruzione if determina se è stato trovato qualcosa e, in tal caso, raccoglie la descrizione in questo modo
desc = Substr( txt, p4 + 1, p5 - p4 - 1 );
p4 e p5 puntano a > e <. quindi p4+1 è il primo carattere di descrizione e p5-p4-1 è la lunghezza della descrizione. La riga successiva ripulisce la descrizione rimuovendo i tag incorporati
desc = Regex( desc, "<[^>]*>", "", globalreplace );
GlobalReplace significa che la regex troverà il modello, sostituirà quel testo con niente, il maggior numero di volte possibile. Il modello corrisponde a <, seguito da zero o più caratteri che non sono >, seguito da > che potrebbe essere un tag 
o un gruppo di tag di stile del testo. Il risultato finale è il testo del tag senza alcuna immagine/colore/carattere/ecc.
Le due righe successive sono simili, per afferrare l'URL piuttosto che la descrizione
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 e p4 (vedi commento) sono le intere posizioni dei tag di collegamento; linktext è il tag di collegamento che include un numero di bit indesiderati. l'hreftext usa regex() per estrarre solo l'URL tra le virgolette href o gli apostrofi. Il modello regex usa backref \1 per assicurarsi che l'apostrofo o le virgolette finali corrispondano a quello iniziale. La prima parentesi aperta nel modello regex crea un gruppo di acquisizione (per \1) che corrisponde a " o '. La seconda parentesi aperta è il gruppo di cattura (per \2) che corrisponde, spostandosi con riluttanza in avanti quanto necessario per abbinare i delimitatori. La terza parentesi aperta è il gruppo di acquisizione 3; i genitori e il raggruppamento non sono realmente necessari. Il risultato, \2, è solo l'URL.
Tutto tranne che fatto: se c'è una descrizione, aggiungi una riga alla tabella e poi, molto importante, fai avanzare la variabile pos!
pos = Max( pos, p5 + 3 );
Max si assicura che non torni indietro alla fine e si blocchi in un loop.
Un modo più veloce
Il codice sopra è abbastanza veloce, ma questo è ancora meglio.
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 0Questa volta il ciclo è all'interno del pattern matcher (usando patrepeat() per spingere il pattern attraverso la stringa). I due pattern
linkpat = "<A>" ) >> linktext + ">" + Pat Arb() >> desctext + "</A>";
scriptpat = "<SCRIPT>" ) + "&amp;amp;amp;gt;" + Pat Arb() + "</SCRIPT>";
stanno facendo due lavori diversi: linkpat abbina del testo e memorizza parti della corrispondenza in linktext e desctext. Scriptpat trova del testo tra e lo ignora. Il tag in HTML definisce una sezione di codice JavaScript che dovrebbe essere ignorata. In questo caso di esempio il JavaScript contiene molte sequenze &amp;amp;amp;lt;a che creano falsi positivi e saltare il JavaScript le elimina. Ne parleremo tra un momento. Il ciclo viene ora eseguito da patmatch() che inizia&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;Alla fine lo show(rc) verifica che il patmatch sia riuscito. Ma prima, il secondo argomento per il patmatch è il pattern&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;che può essere semplificato in tre parti&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;il che significa che ogni passaggio lungo il percorso di uno di questi tre modelli corrisponderà a un testo. Per prima cosa controlla se il linkpat corrisponde; che farà parte del lavoro che è stato semplificato. In caso contrario, verifica se lo scriptpat corrisponde; che salterà alcuni JavaScript. Altrimenti, salta un carattere (di solito un &amp;amp;amp;lt;), più caratteri sufficienti per raggiungere il successivo &amp;amp;amp;lt;. Quindi esegui il loop per di più.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;La parte che è stata semplificata è il JSL che viene eseguito quando linkpat ha esito positivo (ricorda che linkpat salva del testo in linktext e desctext poiché li corrisponde)&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;Dovrebbe assomigliare molto al JSL nel primo esempio che scrive le righe nella tabella dei dati. pattest() è una speciale funzione di corrispondenza dei modelli che restituisce 1 se la corrispondenza deve avere esito positivo e 0 se deve fallire. Qui pattest viene utilizzato per eseguire alcuni JSL e restituisce sempre 1 in modo che il matcher possa andare avanti. Il JSL che esegue non lo è davvero&amp;amp;amp;lt;EM&amp;amp;amp;gt; test&amp;amp;amp;lt;/EM&amp;amp;amp;gt; se il matcher deve eseguire il backup e riprovare; il JSL sta solo aggiornando la tabella.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Credo che questo sia più veloce dell&amp;amp;amp;amp;#39;esempio precedente perché l&amp;amp;amp;amp;#39;esempio precedente chiama contiene() con una posizione iniziale e ha ancora un po&amp;amp;amp;amp;#39; di tempo per farlo. Qui, c&amp;amp;amp;amp;#39;è una singola chiamata al patmatch, con un solo sovraccarico di installazione.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Entrambi gli esempi usano regex per lavori più piccoli all&amp;amp;amp;amp;#39;interno dell&amp;amp;amp;amp;#39;immagine più grande: estrarre il testo del collegamento e l&amp;amp;amp;amp;#39;URL da una breve stringa.&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;Nella risposta anche Text Explorer è una possibile soluzione. Ha una libreria di espressioni regolari già scritte che includono un link grabber, ma non un text grabber descrittivo. Potrebbe essere più facile per alcuni casi, ma probabilmente non sarà più veloce.&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="URL selezionabile in un tag di collegamento &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;URL selezionabile in un tag di collegamento &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;Usa Regex o Esplora testo&amp;amp;amp;lt;SPAN style="font-family: inherit;"&amp;amp;amp;gt; per trovare gli URL in HTML&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;