Récupérer l'URL du HTML@lala demandé dans Comment utiliser la substitution regex <*> ? à propos de saisir URL de HTML . Voici un peu plus de détails sur trois réponses proposées. Tout d'abord, la clause de non-responsabilité : aucun de ces exemples ne fait un bon travail d'analyse HTML, donc tous peuvent trouver des URL qui ne sont pas vraiment là et manquer d'autres URL qui sont vraiment là.
/*
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.
*/
Les problèmes liés à l'analyse HTML consistent principalement à trouver des balises de début et de fin correspondantes et à examiner les données entre elles. Tout le JSL présenté ici peut être déclenché par des fonctionnalités HTML. Mais, cela pourrait être assez bon; faites vos propres tests. Regarde aussi Belle soupe ce qui pourrait être une meilleure réponse.
Voici un extrait d'une page Web HTML montrant un lien (la balise ) avec une URL (la partie href=) et un peu de texte (la partie Discussions) qui seront visibles sur la page.
< a > tag with URL and TextBalise avec URL et Texte
L'objectif est de créer un tableau de données des URL et du texte du lien, un par ligne. Une page Web typique peut contenir environ 100 liens et contenir un demi-mégaoctet de texte. Une lent Une façon d'attaquer le problème (non illustré) est d'écrire une expression régulière simple qui trouve un lien à la fois, de supprimer le lien du texte et de répéter jusqu'à ce qu'il n'y en ait plus. S'il n'y en a qu'un ou deux, tant mieux. Mais s'il pouvait y en avoir des centaines, alors quelques centaines de mégaoctets de données sont manipulés et recherchés.
Un moyen plus rapide consiste à rechercher dans les données, en avançant toujours, en construisant la table de données au fur et à mesure que des liens sont trouvés. Le premier exemple utilise la fonction contains() qui a un troisième argument pour spécifier une position de départ. Contient() renvoie également une position trouvée. En mettant à jour la position de départ juste au-delà de la position trouvée, contains() peut parcourir efficacement le texte sans avoir besoin de sauvegarder ou de modifier le texte.
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>
Le cœur de ce code est la ligne
while( (p1 = Contains( txt, "<A></A>
qui fait un tas de travaux : il utilise pos dans le 3ème argument pour ignorer tout travail précédent, il trouve le prochain rien n'a été trouvé , donc la boucle s'arrête. La prochaine ligne
p4 = Contains( txt, ">", p1 + 3 );
recherche le > correspondant qui termine la balise
p5 = Contains( txt, "", p4 + 1 );
p5 pointera vers la balise qui termine le texte du lien. De nombreuses balises HTML, mais pas toutes, fonctionnent ainsi, une balise de début sans le / et une balise de fin avec la barre oblique. Parfois, les balises de début et de fin sont identiques, en utilisant , mais ce JSL ignore cette possibilité.
L'instruction if détermine si quelque chose a été trouvé, et si c'est le cas, récupère la description comme celle-ci
desc = Substr( txt, p4 + 1, p5 - p4 - 1 );
p4 et p5 pointent le > et <. donc p4+1 est le premier caractère de description, et p5-p4-1 est la longueur de la description. La ligne suivante nettoie la description en supprimant les balises intégrées
desc = Regex( desc, "<[^>]*>", "", globalreplace );
GlobalReplace signifie que la regex trouvera le modèle, remplacera ce texte par rien, autant de fois que possible. Le modèle correspond à <, suivi de zéro ou plusieurs caractères qui ne sont pas >, suivi de > qui peut être une balise 
ou un groupe de balises de style de texte. Le résultat final est le texte de la balise sans aucune image/couleur/police/etc.
Les deux lignes suivantes sont similaires, pour saisir l'URL plutôt que la description
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 et p4 (voir commentaire) sont les positions entières des balises de lien ; linktext est la balise de lien comprenant un certain nombre de bits indésirables. le hreftext utilise regex() pour extraire uniquement l'URL entre les guillemets href ou les apostrophes. Le modèle regex utilise la backref \1 pour s'assurer que l'apostrophe ou le guillemet de fin correspond à celui de début. La première parenthèse ouverte dans le modèle regex crée un groupe de capture (pour \1) qui correspond à " ou '. La deuxième parenthèse ouverte est le groupe de capture (pour \2) qui correspond, avançant à contrecœur aussi loin que nécessaire pour faire correspondre les délimiteurs. La troisième parente ouverte est le groupe de capture 3 ; les parenthèses et le regroupement ne sont pas vraiment nécessaires. Le résultat, \2, n'est que l'URL.
Tout sauf fait : s'il y a une description, ajoutez une ligne au tableau, puis, très important, avancez la variable pos !
pos = Max( pos, p5 + 3 );
Max s'assure qu'il ne recule pas à la fin et ne reste pas coincé dans une boucle.
Un moyen plus rapide
Le code ci-dessus est assez rapide, mais c'est encore mieux.
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 0Cette fois, la boucle est à l'intérieur du matcher de modèle (en utilisant patrepeat() pour pousser le modèle à travers la chaîne.) Les deux modèles
linkpat = "<A>" ) >> linktext + ">" + Pat Arb() >> desctext + "</A>";
scriptpat = "<SCRIPT>" ) + "&amp;amp;amp;gt;" + Pat Arb() + "</SCRIPT>";
font deux tâches différentes : linkpat correspond à du texte et stocke des parties de la correspondance dans linktext et desctext. Scriptpat fait correspondre un texte entre et l'ignore. La balise en HTML définit une section de code JavaScript qui doit être ignorée. Dans cet exemple, le JavaScript contient de nombreuses séquences &amp;amp;amp;lt;a qui créent des faux positifs, et le fait de sauter le JavaScript les élimine. Plus sur cela dans un instant. Le bouclage est maintenant fait par le patmatch() qui commence&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;À la fin, le show(rc) vérifie que le patmatch a réussi. Mais d&amp;amp;amp;amp;#39;abord, le deuxième argument de patmatch est le modèle&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;qui peut être simplifié en trois parties&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;ce qui signifie qu&amp;amp;amp;amp;#39;à chaque étape du chemin, l&amp;amp;amp;amp;#39;un de ces trois modèles correspondra à du texte. Voyez d&amp;amp;amp;amp;#39;abord si le linkpat correspond; qui fera une partie du travail qui a été simplifié. Si ce n&amp;amp;amp;amp;#39;est pas le cas, voyez si le scriptpat correspond&amp;amp;amp;nbsp;; qui sautera du JavaScript. Sinon, sautez un caractère (généralement un &amp;amp;amp;lt;), plus suffisamment de caractères pour atteindre le &amp;amp;amp;lt; suivant. Bouclez ensuite pour plus.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;La partie qui a été simplifiée est le JSL qui s&amp;amp;amp;amp;#39;exécute lorsque le linkpat réussit (rappelez-vous que linkpat enregistre du texte dans linktext et desctext car il les correspond)&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;Cela devrait ressembler beaucoup au JSL du premier exemple qui écrit des lignes dans la table de données. pattest() est une fonction spéciale de correspondance de motifs qui renvoie 1 si la correspondance doit réussir et 0 si elle doit échouer. Ici, pattest est utilisé pour exécuter du JSL et renvoie toujours 1 afin que le matcher puisse avancer. Le JSL qu&amp;amp;amp;amp;#39;il exécute n&amp;amp;amp;amp;#39;est pas vraiment&amp;amp;amp;lt;EM&amp;amp;amp;gt; essai&amp;amp;amp;lt;/EM&amp;amp;amp;gt; si le matcher doit sauvegarder et réessayer&amp;amp;amp;nbsp;; le JSL met juste à jour la table.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Je pense que c&amp;amp;amp;amp;#39;est plus rapide que l&amp;amp;amp;amp;#39;exemple précédent car l&amp;amp;amp;amp;#39;exemple précédent appelle contains() avec une position de départ, et il a encore un peu de temps pour le faire. Ici, il y a un seul appel à patchmatch, avec une seule surcharge de configuration.&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;Les deux exemples utilisent regex pour des travaux plus petits dans une vue d&amp;amp;amp;amp;#39;ensemble&amp;amp;amp;nbsp;: extraire le texte du lien et l&amp;amp;amp;amp;#39;URL d&amp;amp;amp;amp;#39;une chaîne courte.&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;Dans la réponse, Text Explorer est également une solution possible. Il possède une bibliothèque d&amp;amp;amp;amp;#39;expressions régulières pré-écrites qui incluent un outil de saisie de liens, mais pas un outil de saisie de texte descriptif. Cela pourrait être plus facile dans certains cas, mais ne sera probablement pas plus rapide.&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="LienAvecTexteEtURL.png" alt="URL cliquable dans une balise de lien &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 cliquable dans une balise de lien &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;Utiliser Regex ou Text Explorer&amp;amp;amp;lt;SPAN style="font-family: inherit;"&amp;amp;amp;gt; pour trouver des URL en 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;