@拉拉询问于如何使用正则表达式替换<*>?关于抓取网址从超文本标记语言。 以下是三个建议答案的更多细节。 首先,免责声明:这些示例都没有正确解析 HTML,因此它们都可能找到不存在的 URL,而错过其他实际存在的 URL。
/*
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.
*/
解析 HTML 的问题主要是找到匹配的开始和结束标记并查看它们之间的数据。 这里介绍的所有 JSL 都可能被 HTML 功能所困扰。 但是,这可能已经足够好了;做你自己的测试。 另请参阅美丽的汤这可能是一个更好的答案。
下面是 HTML 网页的一个片段,显示了一个带有 URL(href= 部分)的链接( 标记)和一些将在页面上可见的文本(讨论部分)。
< 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带有 URL 和文本的 标签
目标是制作一个包含 URL 和链接文本的数据表,每行一个。 一个典型的网页可能有 100 个左右的链接,并且有半兆字节的文本。 一慢的解决该问题的方法(未显示)是编写一个简单的正则表达式,一次查找一个链接,从文本中删除该链接,然后重复,直到找不到更多链接为止。 如果只有一两个,那就太好了。 但如果可能有 100 个,那么就会操纵和搜索几百兆字节的数据。
更快的方法是搜索数据,始终向前移动,在找到链接时构建数据表。 第一个示例使用 contains() 函数,该函数具有第三个参数来指定起始位置。 Contains() 还返回找到的位置。 通过将起始位置更新到刚好超出找到的位置,contains() 可以有效地浏览文本,而无需备份或修改文本。
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>
该代码的核心是这一行
while( (p1 = Contains( txt, "<A></A>
它做了很多工作:它在第三个参数中使用 pos 来跳过任何先前的工作,它找到下一个开始链接标记的 什么都没找到,因此循环停止。 下一行
p4 = Contains( txt, ">", p1 + 3 );
搜索以 。 p4(见评论)指向那里。 从 p1+3 开始,contains() 会查找 p1 之后的一个,而不是重新查找更早的出现位置。 下一行类似,寻找p4之后的结束标签
p5 = Contains( txt, "", p4 + 1 );
p5 将指向结束链接文本的 标记。 许多(但不是全部)HTML 标记都是这样工作的,开始标记不带 / ,结束标记带斜杠。 有时开始和结束标记是相同的,使用 ,但此 JSL 忽略了这种可能性。
if 语句确定是否找到了某些内容,如果是,则获取如下描述
desc = Substr( txt, p4 + 1, p5 - p4 - 1 );
p4 和 p5 分别指向 > 和 <。所以p4+1是第一个描述字符,p5-p4-1是描述的长度。 下一行通过删除嵌入标签来清理描述
desc = Regex( desc, "<[^>]*>", "", globalreplace );
GlobalReplace 意味着正则表达式将找到该模式,尽可能多次地将该文本替换为空。 该模式匹配 <,后跟零个或多个不是 > 的字符,后跟 >,它可能是 
p1和p4(见注释)是整个链接标签位置; linktext 是包含许多不需要的位的链接标记。 hreftext 使用 regex() 只提取 href 引号或撇号之间的 URL。 正则表达式模式使用 backref \1 来确保尾随撇号或引号与前导撇号或引号匹配。 正则表达式模式中的第一个左括号创建与“或”匹配的捕获组(对于 \1)。 第二个左括号是匹配的捕获组(对于 \2),不情愿地向前移动到需要在分隔符之间匹配的位置。 第三个左括号是捕获组 3;括号和分组并不是真正需要的。 结果 \2 只是 URL。