從 HTML 中獲取 URL@拉拉問進來如何使用正則表達式替換<*>?關於搶網址從HTML . 以下是關於三個建議答案的更多細節。 首先,免責聲明:這些示例都不能正確解析 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 帶有 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" 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>
該代碼的核心是行
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 意味著正則表達式將找到模式,盡可能多次替換該文本。 該模式匹配 <,後跟零個或多個不是 > 的字符,然後是 >,它可能是一個 
標籤或一堆文本樣式標籤。 最終結果是沒有任何圖片/顏色/字體/等的標籤文本。
接下來的兩行類似,用於獲取 URL 而不是描述
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 和 p4 (見註釋)是整個鏈接標籤位置; linktext 是包含許多不需要的位的鏈接標籤。 hreftext 使用 regex() 僅提取 href 引號或撇號之間的 URL。 正則表達式模式使用 backref \1 來確保尾隨的撇號或引號與前導的相匹配。 正則表達式模式中的第一個開放括號構成一個匹配“或”的捕獲組(用於 \1)。 第二個開放括號是匹配的捕獲組(用於 \2),不情願地向前移動,直到需要在分隔符之間匹配。 第三個開放括號是捕獲組 3;括號和分組並不是真正需要的。 結果 \2 就是 URL。
幾乎完成:如果有描述,在表格中添加一行,然後,非常重要的是,推進 pos 變量!
pos = Max( pos, p5 + 3 );
Max 確保它不會在最後倒退並陷入循環。
更快的方法
上面的代碼非常快,但這更好。
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 0這次循環在模式匹配器內部(使用 patrepeat() 將模式推入字符串。)這兩個模式
linkpat = "<A>" ) >> linktext + ">" + Pat Arb() >> desctext + "</A>";
scriptpat = "<SCRIPT>" ) + "&amp;amp;amp;gt;" + Pat Arb() + "</SCRIPT>";
正在做兩個不同的工作:linkpat 匹配一些文本並將匹配的部分存儲在 linktext 和 desctext 中。 Scriptpat 匹配 之間的一些文本並忽略它。 HTML 中的 標記定義了應該被忽略的 JavaScript 代碼部分。 在這個示例中,JavaScript 包含許多會產生誤報的 &amp;amp;amp;lt;a 序列,跳過 JavaScript 會消除它們。 稍後會詳細介紹。 循環現在由開始的 patmatch() 完成&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;最後,show(rc) 驗證 patmatch 成功。 但首先,patmatch 的第二個參數是模式&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;可以簡化為三個部分&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;這意味著這三種模式之一的每一步都將匹配一些文本。 先看linkpat是否匹配;這將完成一些被簡化的工作。 如果沒有,看看 scriptpat 是否匹配;這將跳過一些 JavaScript。 否則,跳過一個字符(通常是 &amp;amp;amp;lt;),加上足夠的字符以到達下一個 &amp;amp;amp;lt;。 然後循環更多。&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;被簡化的部分是在 linkpat 成功時運行的 JSL(請記住,linkpat 將一些文本保存在 linktext 和 desctext 中,因為它與它們匹配)&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;這應該看起來很像第一個示例中的 JSL,它將行寫入數據表。 pattest() 是一個特殊的模式匹配函數,如果匹配成功則返回 1,如果匹配失敗則返回 0。 這裡 pattest 用於運行一些 JSL 並且總是返回 1 以便匹配器可以向前移動。 它運行的 JSL 並不是真的&amp;amp;amp;lt;EM&amp;amp;amp;gt;測試&amp;amp;amp;lt;/EM&amp;amp;amp;gt;如果匹配器需要備份並重試; JSL 只是更新表。&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;我相信這比前面的例子要快,因為前面的例子調用 contains() 時有一個起始位置,而且它還有一些設置時間來做這件事。 在這裡,只有一次對 patmatch 的調用,只有一次設置開銷。&amp;amp;amp;lt;/P&amp;amp;amp;gt;&amp;amp;amp;lt;P&amp;amp;amp;gt;這兩個示例都將正則表達式用於更大範圍內的較小工作:從短字符串中提取鏈接文本和 URL。&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;在答案中,文本資源管理器也是一種可能的解決方案。 它有一個預先編寫的正則表達式庫,其中包括一個鏈接抓取器,但沒有描述性文本抓取器。 在某些情況下可能會更容易,但可能不會更快。&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="&amp;amp;amp;lt;a&amp;amp;amp;gt; 鏈接標籤中的可點擊 URL" /&amp;amp;amp;gt;&amp;amp;amp;lt;span class="lia-inline-image-caption" onclick="event.preventDefault();"&amp;amp;amp;gt;&amp;amp;amp;lt;a&amp;amp;amp;gt; 鏈接標籤中的可點擊 URL&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;使用正則表達式或文本資源管理器&amp;amp;amp;lt;SPAN style="font-family: inherit;"&amp;amp;amp;gt;在 HTML 中查找 URL&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;