HTML에서 URL 가져오기@라라 에 물었다 정규식 대체 <*>를 어떻게 사용할 수 있습니까? 잡는 것에 대해 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 기능에 의해 작동될 수 있습니다. 그러나 충분히 좋을 수 있습니다. 자신의 테스트를 수행합니다. 또한 참조 아름다운 수프 더 나은 답변이 될 수 있습니다.
다음은 페이지에 표시될 URL(href= 부분) 및 약간의 텍스트(토론 부분)가 있는 링크( 태그)를 보여주는 HTML 웹 페이지의 일부입니다.
< a > tag with URL and TextURL 및 텍스트가 있는 < a > 태그
목표는 URL과 링크 텍스트의 데이터 테이블을 행당 하나씩 만드는 것입니다. 일반적인 웹 페이지에는 100개 정도의 링크와 0.5MB의 텍스트가 있습니다. 하나 느린 문제를 공격하는 방법(표시되지 않음)은 한 번에 하나의 링크를 찾고 텍스트에서 링크를 제거하고 더 이상 찾을 수 없을 때까지 반복하는 간단한 정규식을 작성하는 것입니다. 한 두 개만 있으면 훌륭합니다. 그러나 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는 정규 표현식이 패턴을 찾고 가능한 한 많은 텍스트를 아무 것도 없는 것으로 대체한다는 것을 의미합니다. 패턴은 <와 일치하며, 그 뒤에 >가 아닌 0개 이상의 문자가 오고, 그 뒤에 
태그 또는 텍스트 스타일 태그 묶음일 수 있는 >가 옵니다. 최종 결과는 그림/색상/글꼴 등이 없는 태그의 텍스트입니다.
다음 두 줄은 설명이 아닌 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;