@lala preguntado en ¿Cómo se puede usar la sustitución de expresiones regulares <*>? sobre agarrar URL de HTML . Aquí hay un poco más de detalles sobre tres respuestas propuestas. Primero, el descargo de responsabilidad: ninguno de estos ejemplos hace un trabajo adecuado al analizar HTML, por lo que todos ellos pueden encontrar URL que realmente no están allí y perder otras URL que realmente están allí.
/*
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.
*/
Los problemas al analizar HTML se relacionan principalmente con la búsqueda de etiquetas de inicio y final coincidentes y la observación de los datos entre ellas. Todo el JSL presentado aquí se puede tropezar con las características de HTML. Pero, podría ser lo suficientemente bueno; haz tus propias pruebas. Ver también hermosa sopa que podría ser una mejor respuesta.
Aquí hay un fragmento de una página web HTML que muestra un enlace (la etiqueta ) con una URL (la parte href=) y un poco de texto (la parte Discusiones) que será visible en la página.
< a > tag with URL and Text< a > tag with URL and Text< a > tag with URL and Text< a > tag with URL and Text< a > tag with URL and Text< a > etiqueta con URL y texto
El objetivo es hacer una tabla de datos de las URL y el texto del enlace, uno por fila. Una página web típica puede tener alrededor de 100 enlaces y tener medio megabyte de texto. Uno lento La forma de atacar el problema (que no se muestra) es escribir una expresión regular simple que encuentre un enlace a la vez, eliminar el enlace del texto y repetir hasta que no se pueda encontrar más. Si solo hay uno o dos, genial. Pero si pudiera haber 100, entonces se manipulan y buscan unos pocos cientos de megabytes de datos.
Una forma más rápida es buscar a través de los datos, siempre avanzando, construyendo la tabla de datos a medida que se encuentran los enlaces. El primer ejemplo usa la función contains() que tiene un tercer argumento para especificar una posición inicial. Contiene () también devuelve una posición encontrada. Al actualizar la posición de inicio un poco más allá de la posición encontrada, contains() puede examinar el texto de manera eficiente sin necesidad de realizar una copia de seguridad o modificar el texto.
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"> 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>
El corazón de ese código es la línea.
while( (p1 = Contains( txt, "<A></A>
que está haciendo un montón de trabajos: usa pos en el tercer argumento para omitir cualquier trabajo anterior, encuentra el siguiente Nada Encontrado , por lo que el ciclo se detiene. la siguiente línea
p4 = Contains( txt, ">", p1 + 3 );
busca la coincidencia > que finaliza la etiqueta
p5 = Contains( txt, "", p4 + 1 );
p5 apuntará a la etiqueta que finaliza el texto del enlace. Muchas, pero no todas, las etiquetas HTML funcionan así, una etiqueta de inicio sin / y una etiqueta de fin con la barra inclinada. A veces, la etiqueta inicial y final son las mismas, usando , pero este JSL ignora esa posibilidad.
La declaración if determina si se encontró algo y, de ser así, recoge la descripción de esta manera
desc = Substr( txt, p4 + 1, p5 - p4 - 1 );
p4 y p5 apuntan a > y <. entonces p4+1 es el primer carácter de descripción y p5-p4-1 es la longitud de la descripción. La siguiente línea limpia la descripción eliminando las etiquetas incrustadas
desc = Regex( desc, "<[^>]*>", "", globalreplace );
GlobalReplace significa que la expresión regular encontrará el patrón, reemplazará ese texto con nada, tantas veces como sea posible. El patrón coincide con <, seguido de cero o más caracteres que no son >, seguidos de >, que podría ser una etiqueta o un montón de etiquetas de estilo de texto. El resultado final es el texto de la etiqueta sin ninguna imagen/color/fuente/etc.
Las siguientes dos líneas son similares, para obtener la URL en lugar de la descripción.
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 y p4 (ver comentario) son las posiciones completas de la etiqueta de enlace; linktext es la etiqueta del enlace que incluye una serie de bits no deseados. hreftext usa regex() para extraer solo la URL entre las comillas href o apóstrofes. El patrón de expresiones regulares usa el backref \1 para asegurarse de que el apóstrofo final o las comillas coincidan con el inicial. El primer paréntesis abierto en el patrón de expresiones regulares crea un grupo de captura (para \1) que coincide con " o '. El segundo paréntesis abierto es el grupo de captura (para \2) que coincide, avanzando a regañadientes tanto como sea necesario para coincidir entre los delimitadores. El tercer paréntesis abierto es el grupo de captura 3; los paréntesis y la agrupación no son realmente necesarios. El resultado, \2, es solo la URL.
Todo menos hecho: si hay una descripción, agregue una fila a la tabla y luego, muy importante, ¡avance la variable pos!
pos = Max( pos, p5 + 3 );
Max se asegura de que no retroceda al final y se atasque en un bucle.
Una forma más rápida
El código anterior es bastante rápido, pero este es aún mejor.
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;amp;amp;amp;amp;amp;lt;a&amp;amp;amp;amp;amp;amp;amp;amp;gt; links and one for &amp;amp;amp;amp;amp;amp;amp;amp;lt;script&amp;amp;amp;amp;amp;amp;amp;amp;gt; to skip over
linkpat = "&amp;amp;amp;amp;amp;amp;amp;amp;lt;a " + Pat Break( "&amp;amp;amp;amp;amp;amp;amp;amp;gt;" ) &amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;gt; linktext + "&amp;amp;amp;amp;amp;amp;amp;amp;gt;" + Pat Arb() &amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;gt; desctext + "&amp;amp;amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;amp;amp;gt;";
scriptpat = "&amp;amp;amp;amp;amp;amp;amp;amp;lt;script" + Pat Break( "&amp;amp;amp;amp;amp;amp;amp;amp;gt;" ) + "&amp;amp;amp;amp;amp;amp;amp;amp;gt;" + Pat Arb() + "&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;Esta vez, el ciclo está dentro del comparador de patrones (usando patrepeat() para empujar el patrón a través de la cadena). Los dos patrones&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 = "&amp;amp;amp;lt;A&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&amp;amp;amp;gt;" ) + "&amp;amp;amp;amp;amp;amp;amp;amp;gt;" + Pat Arb() + "&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;están haciendo dos trabajos diferentes: linkpat coincide con algún texto y almacena partes de la coincidencia en linktext y desctext. Scriptpat coincide con algún texto entre &amp;amp;amp;lt;script ...="" y="" ...=""&amp;amp;amp;gt;&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;/LINGO-BODY&amp;amp;amp;gt;&amp;amp;amp;lt;lingo-sub id="lingo-sub-576161" slang="en-US" mode="CREATE"&amp;amp;amp;gt;Re: Obtener URL desde HTML&amp;amp;amp;lt;/lingo-sub&amp;amp;amp;gt;&amp;amp;amp;lt;lingo-body id="lingo-body-576161" slang="en-US" mode="CREATE"&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;Gracias &amp;amp;amp;lt;a href="https://community.jmp.com/t5/user/viewprofilepage/user-id/982"&amp;amp;amp;gt;@Craige_Hales&amp;amp;amp;lt;/a&amp;amp;amp;gt;&amp;amp;amp;lt;/p&amp;amp;amp;gt;
&amp;amp;amp;lt;p&amp;amp;amp;gt;Encontré este &amp;amp;amp;lt;a href="https://uibakery.io/regex-library/url" target="_blank" rel="nofollow noopener noreferrer"&amp;amp;amp;gt;https://uibakery.io/regex-library/url&amp;amp;amp;lt;/a&amp;amp;amp;gt; en línea,&amp;amp;amp;lt;/p&amp;amp;amp;gt;
&amp;amp;amp;lt;p&amp;amp;amp;gt;¿Cómo puedo usarlo en una fórmula de columna suponiendo que tengo otra columna con textos que incluyen URL?&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;/lingo-body&amp;amp;amp;gt;</SCRIPT>