XHTML 자체 포함 태그를 제외한 정규식 일치 공개 태그


1473

이 모든 시작 태그와 일치해야합니다.

<p>
<a href="foo">

그러나 이것들은 아닙니다.

<br />
<hr class="foo" />

나는 이것을 생각해 냈고 내가 올바르게 가지고 있는지 확인하고 싶었다. 만 캡처하고 a-z있습니다.

<([a-z]+) *[^/]*?>

나는 그것이 말한다 :

  • 보다 작게 찾기
  • az를 한 번 이상 찾아서 캡처 한 다음
  • 0 개 이상의 공백을 찾은 다음
  • 을 제외하고 탐욕스러운 문자를 0 번 이상 /찾은 다음
  • 보다 큰 찾기

내가 그 권리를 가지고 있습니까? 그리고 더 중요한 것은 어떻게 생각하십니까?

답변:


4417

[X] HTML을 정규식으로 구문 분석 할 수 없습니다. 정규식으로 HTML을 파싱 할 수 없기 때문입니다. 정규식은 HTML을 올바르게 구문 분석하는 데 사용할 수있는 도구가 아닙니다. 이전에 HTML 및 정규식 질문에 여러 번 답변 했으므로 정규식을 사용하면 HTML을 사용할 수 없습니다. 정규식은 HTML에 의해 사용 된 구문을 이해하기에 충분히 정교하지 않은 도구입니다. HTML은 정규 언어가 아니므로 정규 표현식으로 구문 분석 할 수 없습니다. 정규식 쿼리는 HTML을 의미있는 부분으로 분류 할 수 없습니다. 너무 많은 시간이지만 그것은 나에게 도착하지 않습니다. Perl에서 사용하는 향상된 불규칙 정규 표현식조차도 HTML 구문 분석 작업에 달려 있지 않습니다. 당신은 결코 나를 부수 지 않을 것입니다. HTML은 정규 표현식으로 구문 분석 할 수 없을 정도로 복잡한 언어입니다. Jon Skeet조차도 정규 표현식을 사용하여 HTML을 구문 분석 할 수 없습니다. 정규식으로 HTML을 구문 분석하려고 시도 할 때마다 부정한 자식은 처녀의 피를 흘리고 러시아 해커는 webapp를 전복합니다. 정규 표현식 소환으로 HTML을 파싱하면 영혼이 살아있는 영역으로 오염되었습니다. HTML과 정규식은 사랑, 결혼, 의식적인 보살핌과 같이 어울립니다. <center>가 너무 늦을 수 없습니다. 같은 개념 공간에서 정규 표현식과 HTML의 힘이 너무 물 퍼티처럼 당신의 마음을 파괴합니다. 정규식으로 HTML을 파싱하면 기본 다국어 비행기로 이름을 표현할 수없는 분을 위해 비인간적 인 수고를 할 수있는 Them과 그 신성 모독 방법을 제공합니다. HTML-plus-regexp는 당신이 관찰하는 동안 지각의 신경을 유동화시킬 것입니다.너무 늦었다 너무 늦었 어 우리는 chi͡ld의 뭉치를 구할 수 없다 정규 표현식이 모든 살아있는 조직을 소비하도록 보장한다 (이전에 예언 한대로 HTML을 제외하고) 친애하는 주님 우리가 누군가가 어떻게 정규식을 사용 하여이 채찍살아남을 수 있는지 분석 할 수 있도록 도와주십시오. HTML은 공포 고문 및 보안 구멍의 영원한 인류 운명했다 REGE를 사용하여 프로세스 HTML을 도구로 X를 브리의 확립 이 세계 사이의 채널 및 손상 엔티티의 공포 영역 (SGML 엔티티와 같은,하지만 더 손상을) glimp 단순한 자체의를 레지의 세계 HTML에 대한 전 파서는 것 인 tantly 전송 AP 통신 rogrammer의 의식은 내가 아 NTO ORL D 끊임없는 비명의 그가 온다의 간악한 SL ithy 정규식 감염 줘야의 당신의 HT 바우어 리터 Visual Basic에서 같은 모든 시간 ML 파서, 응용 프로그램과 존재는 악화 그가 온다 그는 COM ES 하지 Fi를 GHT의 시간 전자 제공, HI 의 부정 래디언스 드 stro҉ying 모든 깨달음, HTML 태그 누출 fr̶ǫm 요 우르 눈처럼 LIQ UID P는 아인, 일반 특급 재의 노래 ssion 구문 분석 exti 것 MOR의 목소리 nguish 은 SP에서 탈 사람이 여기 나는 당신이 볼 수 볼 수 있습니다 그것은 그것을 다운 t는 그 F inal snuf닐렌 O F 거짓이 남자 ALL IS 잃은 S의 LL I SL일 OST 즉 그가 올 포니 그가 COM들 그 공동 ES S t를 ICH 또는 permeat ES 알 L MY FAC E MY FACE ᵒh 신 N O NO NOO O ON Θ 정지 t 그 *가 ̶͑̾̾ GL ES ͎a̧͈͖r̽̾̈́͒͑eN 구약 ZA ͨ ̘̝̙ͤ͂̾̆ ZA Ό Ό Ό Ό ̘ ̘ ͠ ͠ ͠ ͠ ̡̅̾̎ ̡̅̾̎ ̡̅̾̎ ̡ P P ͍̭ P P ̡ ͨ͊ ̡̅̾̎ ̡̅̾̎ ̡̅̾̎ ̚ ̡ ̡ ͪ̈́̀ ̡̅̾̎ ̡̅̾̎ ̧̬̩͘ ͭ̏ͥͮ ͭ̏ͥͮ ͭ̏ͥͮ ͭ̏ͥͮ ͭ̏ͥͮ ͭ̏ͥͮ ͭ̏ͥͮ ͭ̏ͥͮ ͭ̏ͥͮ C ͭ̏ͥͮ ̷̙ ͭ̏ͥͮ ͮ͏ ͮ͏ ͮ͏


XML 파서를 대신 사용해 보셨습니까?


사회 주의자 주

이 게시물은 내용의 부적절한 편집을 방지하기 위해 잠겨 있습니다. 게시물은 모양과 똑같이 보입니다. 내용에 아무런 문제가 없습니다. 주의를 끌기 위해 신고하지 마십시오.


179
Kobi : Regex Officer와 함께 HTML을 구문 분석하지 마십시오. 우리가 몇 번이나 말하더라도 매일 매일 멈출 수는 없습니다. 다른 사람이 조금 싸울 수있는 잃어버린 원인입니다. 필요한 경우 정규식으로 HTML을 구문 분석하십시오. 삶과 죽음이 아니라 코드가 깨졌습니다.
bobince

27
RegEx를 사용 하여이 답변을 구문 분석 할 수 있습니까?
Chris Porter

2
이 게시물을 볼 수없는 경우, 여기 모든 영광 그것의 screencapture는 다음과 같습니다 imgur.com/gOPS2.png
앤드류 Keeton

3247

정규 표현식 만 있는 임의의 HTML은 불가능하지만, 제한된 HTML 집합 을 구문 분석하는 데 사용하는 것이 때때로 적절합니다 .

데이터를 긁어 데이터베이스에 넣을 작은 HTML 페이지 집합이 있으면 정규 표현식이 제대로 작동 할 수 있습니다. 예를 들어, 저는 최근에 의회 웹 사이트에서 벗어난 호주 연방 대표의 이름, 정당 및 지구를 얻고 싶었습니다. 이것은 제한된 일회성 직업이었습니다.

정규식은 나를 위해 잘 작동했으며 설정이 매우 빨랐습니다.


131
또한 대형 문서에서 상당히 규칙적인 형식의 데이터를 스크랩하면 일반적인 파서보다 스캔 및 정규식을 신중하게 사용하여 더 빠르게 진행됩니다. 정규식 코딩에 익숙하다면 xpath 코딩보다 코딩 속도가 더 빠릅니다. 그리고 긁는 것의 변화에 ​​대해 거의 확실하지 않습니다. 그래서 bleh.
Michael Johnston

255
@MichaelJohnston "약한 연약한"? 거의 확실하지 않습니다. 정규 표현식은 XML 파서가 자동으로 무시할 수있는 것보다 텍스트 형식 세부 사항을 관리합니다. &foo;인코딩과 CDATA섹션 간을 전환 하시겠습니까? HTML 축소기를 사용하여 브라우저에서 렌더링되지 않는 문서의 모든 공백을 제거합니까? XML 파서는 상관하지 않으며 잘 작성된 XPath 문도 마찬가지입니다. 반면 정규 표현식 기반 "구문 파서"
Charles Duffy

41
@CharlesDuffy 한 번의 작업은 괜찮습니다. 공간에는 \ s +를 사용합니다.
quantum

68
@xiaomao 실제로, 나머지 시간 "당신을 위해 작동"에 실패하는 80 % 솔루션을 얻기 위해 모든 문제와 해결 방법을 알아야하는 경우, 나는 당신을 막을 수 없습니다. 한편, 나는 구문 적으로 유효한 XML의 100 %에서 작동하는 파서를 사용하여 울타리 너머에 있습니다.
찰스 더피

374
한 번은 동일한 HTML 템플릿으로 ~ 10k 페이지에서 일부 데이터를 가져와야했습니다. 파서가 질식하게 만든 HTML 오류로 가득 차 있었고 모든 스타일링은 인라인 또는 <font>기타로 이루어졌습니다. DOM을 탐색하는 데 도움이되는 클래스 나 ID가 없습니다. "올바른"접근 방식으로 하루 종일 싸우고 나서 마침내 정규식 솔루션으로 전환하여 한 시간 안에 작동했습니다.
Paul A Jungwirth

2037

여기에 결함이 있다고 생각하면 HTML은 Chomsky Type 2 문법 (문맥이없는 문법) 이고 RegEx는 Chomsky Type 3 문법 (정규 문법) 입니다. Type 2 문법은 근본적으로 Type 3 문법보다 복잡하기 때문에 ( Chomsky 계층 참조 ) RegEx로 XML을 구문 분석 하는 것은 수학적으로 불가능 합니다.

그러나 많은 사람들이 시도 할 것이고, 어떤 사람들은 성공을 요구할 수도 있습니다.


225
OP는 XHTML의 매우 제한된 하위 집합 인 시작 태그를 구문 분석하도록 요청하고 있습니다. (X) HTML을 CFG로 만드는 것은 문법 규칙에서와 같이 다른 요소의 시작 태그와 끝 태그 사이에 요소가있을 가능성이 있습니다 A -> s A e. (X) HTML 않습니다 하지 이 속성이 시작 태그 : 시작 태그는 다른 시작 태그를 포함 할 수 없습니다. OP가 구문 분석하려는 서브 세트는 CFG가 아닙니다.
LarsH

101
CS 이론에서 정규 언어 컨텍스트가없는 언어의 엄격한 하위 집합이지만 주류 프로그래밍 언어의 정규 표현식 구현이 더 강력합니다. noulakaz.net/weblog/2007/03/18/…에 설명 된 바와 같이, 소위 "정규 표현식"은 단항의 소수를 확인할 수 있습니다. 이는 확실히 CS 이론의 정규 표현식으로는 달성 할 수없는 것입니다.
Adam Mihalcin

11
@eyelidlessness : 모든 "CFG에 동일한"만 "적용 되는가? 즉, (X) HTML 입력이 제대로 구성되지 않으면 완전한 XML 파서조차 안정적으로 작동하지 않습니다. 어쩌면 당신이 말하는 "실제 사용자 에이전트에서 구현 된 (()) HTML 구문 오류"의 예를 들었다면, 당신이 낫고있는 것을 이해할 것입니다.
LarsH

82
@AdamMihalcin이 옳습니다. 가장 현존하는 정규식 엔진은 Chomsky Type 3 문법보다 강력합니다 (예 : 욕심없는 매칭, 역 참조). Perl과 같은 일부 정규식 엔진은 Turing이 완료되었습니다. 이것들조차 HTML을 파싱하기에 열악한 도구라는 것은 사실이지만, 종종 언급되는 논쟁은 그 이유가 아닙니다.
dubiousjim

27
이것은 가장 "완전하고 짧은"답변입니다. 그것은 사람들이 형식적인 문법과 언어의 기초를 배우고 희망적으로 약간의 수학을 배우도록하여 다항식 시간에 NP 작업을 해결하는 것과 같은 희망없는 일에 시간을 허비하지 않도록합니다.
mishmashru

1332

이 사람들의 말을 듣지 마십시오. 당신은 완전히 수 있습니다 당신은 작은 조각으로 작업을 중단하는 경우 정규식과 문맥 자유 문법을 구문 분석합니다. 다음 순서대로 각각을 수행하는 스크립트를 사용하여 올바른 패턴을 생성 할 수 있습니다.

  1. 중단 문제를 해결하십시오.
  2. 원을 제곱합니다.
  3. 출장 세일즈맨 문제를 O (log n) 이하로 해결하십시오. 그 이상이면 RAM이 부족하고 엔진이 정지합니다.
  4. 패턴이 상당히 커지므로 임의의 데이터를 손실없이 압축하는 알고리즘이 있는지 확인하십시오.
  5. 거의 전부-모든 것을 0으로 나눕니다. 쉬워요.

나는 마지막 부분을 스스로 끝내지 못했지만 점점 가까워지고 있음을 알고 있습니다. CthulhuRlyehWgahnaglFhtagnException어떤 이유로 든 s를 계속 던지 므로 VB 6으로 이식하고을 사용 On Error Resume Next합니다. 벽에 열린 이상한 문을 조사하면 코드로 업데이트하겠습니다. 흠.

PS Pierre de Fermat도 그 방법을 알아 냈지만, 그가 쓴 마진은 코드에 비해 크지 않았습니다.


80
0으로 나누는 것은 다른 사람들보다 훨씬 쉬운 문제입니다. 일반 부동 소수점 산술 (모든 사람이되어야하지만 아무도는 안 됨)이 아닌 간격을 사용하는 경우 행복하게 [간격 포함]을 0으로 나눌 수 있습니다. 결과는 단순히 플러스와 마이너스 무한대를 포함하는 간격입니다.
rjmunro 2016 년

148
Fermat의 작은 마진 문제는 최신 텍스트 편집 소프트웨어의 부드러운 마진으로 해결되었습니다.
kd4ttc

50
: 페르마의 작은 마진 문제는 제로로 글꼴 크기를 설정하여 랜달 먼로에 의해 해결되었다 xkcd.com/1381
heltonbiker을

29
참고 : Fermat의 문제 는 1995 년에 실제로 해결되었으며 358 년이 걸렸습니다.
jmiserez

10
콜드 퓨전에서 나온 브라운 래칫을 대신 사용하여 끈적 끈적한 0으로 나누는 단계를 우회 할 수 있었지만 우주 상수를 제거 할 때만 작동합니다.
Tim Lehner

1072

면책 조항 : 옵션이있는 경우 파서를 사용하십시오. 그건 ...

이것은 HTML 태그와 일치시키기 위해 내가 사용하는 정규식입니다!

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>

완벽하지는 않지만 많은 HTML 을 통해이 코드를 실행했습니다 . 심지어 <a name="badgenerator"">웹에 나타나는 것과 같은 이상한 것들도 포착 합니다.

자체 포함 태그와 일치하지 않도록 Kobi 의 부정적인 모양 을 사용하고 싶을 것입니다 .

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+(?<!/\s*)>

또는 그렇지 않은 경우 결합하십시오.

downvoters : 실제 제품의 작동 코드입니다. 이 페이지를 읽는 사람은 누구나 HTML에서 정규 표현식을 사용하는 것이 사회적으로 허용된다는 인상을받을 것입니다.

주의 사항 :이 정규 표현식은 여전히 ​​CDATA 블록, 주석 및 스크립트 및 스타일 요소가있는 경우 분류됩니다. 좋은 소식은 정규식을 사용하는 사람들을 제거 할 수 있다는 것입니다 ...


94
내가 뭔가 함께 갈 것이라고 :-) 보편적으로 완벽하게되지 않는 약 울게보다 제정신 일에 작품
prajeesh 쿠마

55
누군가 HTML 내에서 CDATA를 사용하고 있습니까?
Danubian Sailor

16
따라서 정규 표현식으로 만 구문 분석 문제를 해결하지는 않지만 파서의 일부로 작동 할 수 있습니다. 추신 : 작동하는 제품이 좋은 코드를 의미하지는 않습니다. 범죄는 없지만 이것은 산업 프로그래밍이 어떻게 작동하고 돈을
받는가

32
정규식 시작은 가능한 가장 짧은 유효한 HTML에서 실패합니다 <!doctype html><title><</title>. 간단한 동안 '<!doctype html><title><</title>'.match(/<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g)반환 ["<!doctype html>", "<title>", "<</title>"]해야합니다 ["<title>", "</title>"].

2
주어진 예제와 일치하고 일치하지 않으면 /<.([^r>][^>]*)?>/g 작동 :-) // javascript : '<p> <a href = "foo"> <br /> <hr class = "foo"/>'.match(/<.([^r>][^>]
imma

506

지구가 둥글다는 말을하는 사람들이 있습니다. 그들은 거짓말하고있다.

정규 표현식이 재귀 적이 지 않아야한다고 말하는 사람들이 있습니다. 그들은 당신을 제한하고 있습니다. 그들은 당신을 정복해야하며, 당신을 무지하게 유지함으로써 그것을합니다.

당신은 그들의 현실에서 살거나 빨간 약을 먹을 수 있습니다.

Lord Marshal과 마찬가지로 (Marshal .NET 클래스의 친척입니까?) Underverse Stack Based Regex-Verse를 보았고 상상할 수없는 지식으로 돌아 왔습니다 . 예, 나는 그들을 보호하는 Old One 또는 Two가 있다고 생각하지만 TV에서 축구를보고 있었기 때문에 어렵지 않았습니다.

XML 사례는 매우 간단하다고 생각합니다. base64로 압축을 풀고 코딩 한 RegEx (.NET 구문)는 다음과 같은 방법으로 쉽게 이해할 수 있습니다.

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
+r/vD34mUADO1P4/AQAA//8=

설정할 옵션은 RegexOptions.ExplicitCapture입니다. 찾고있는 캡처 그룹은 ELEMENTNAME입니다. 캡처 그룹 ERROR이 비어 있지 않으면 구문 분석 오류가 발생했으며 정규식이 중지되었습니다.

사람이 읽을 수있는 정규식으로 다시 변환하는 데 문제가 있으면 다음과 같은 도움이됩니다.

static string FromBase64(string str)
{
    byte[] byteArray = Convert.FromBase64String(str);

    using (var msIn = new MemoryStream(byteArray))
    using (var msOut = new MemoryStream()) {
        using (var ds = new DeflateStream(msIn, CompressionMode.Decompress)) {
            ds.CopyTo(msOut);
        }

        return Encoding.UTF8.GetString(msOut.ToArray());
    }
}

당신이 확실하지 않으면, 아니, 나는 농담이 아닙니다 (그러나 아마도 거짓말하고 있습니다). 작동합니다. 나는 그것을 테스트하기 위해 수많은 단위 테스트를 만들었으며 심지어 적합성 테스트 (일부)를 사용했습니다 . 완전한 파서가 아닌 토크 나이저이므로 XML을 구성 요소 토큰으로 만 분할합니다. DTD를 구문 분석 / 통합하지 않습니다.

오 ... 정규식의 소스 코드를 원한다면 몇 가지 보조 방법을 사용하십시오.

정규식은 XML 또는 전체 일반 정규식을 토큰 화합니다.


68
좋은 주님, 그것은 방대합니다. 가장 큰 질문은 왜? 모든 현대 언어에는 XML 파서가 있다는 것을 알고 있습니까? 3 줄처럼 모든 것을 할 수 있고 효과가 있는지 확인하십시오. 또한 순수한 정규 표현식이 특정 작업을 수행 할 없다는 것을 알고 있습니까? 하이브리드 정규식 / 제국 코드 파서를 만들지 않았다면, 그렇지 않은 것 같습니다. 무작위 데이터도 압축 할 수 있습니까?
저스틴 모건

113
@Justin 이유가 필요 없습니다. 그것은 할 수 있었고 (불법적이거나 부도덕하지 않았습니다), 나는 그것을했습니다. 우리가 인정하는 것 (Napoleon Hill)을 제외하고는 마음에 제한이 없습니다 ... 현대 언어는 XML을 파싱 할 수 있습니까? 정말? 그리고 나는 그것이 불법이라고 생각했습니다! :-)
xanatos

76
선생님, 저는 확신합니다. 이 코드를 퍼페 추얼 모션 머신을위한 커널의 일부로 사용할 것입니다. 특허청의 바보가 내 응용 프로그램을 계속 거부한다고 믿을 수 있습니까? 글쎄, 내가 보여 줄게. 나는 그들 모두를 보여줄 것이다!
저스틴 모건

31
@ 저스틴 그래서 Xml 파서는 정의에 따라 버그가 없지만 Regex는 그렇지 않습니다. Xml 파서가 정의에 의해 버그가 없다면 XML이 충돌하고 0 단계로 돌아갑니다. Xml 파서와이 정규식은 모두 "법적"을 모두 파싱하려고합니다. "XML. "불법적 인"XML을 구문 분석 할 수 있습니다. 버그가 둘 다 충돌 할 수 있습니다. C # XmlReader는이 정규식보다 확실히 테스트되었습니다.
xanatos

31
아니오, 버그가 없습니다 : 1) 모든 프로그램에 하나 이상의 버그가 있습니다. 2) 모든 프로그램에는 하나 이상의 불필요한 소스 코드가 포함되어 있습니다. 3) # 1과 # 2에 의해 그리고 논리적 인 유도를 사용하면, 프로그램이 버그로 한 줄의 코드로 축소 될 수 있음을 증명하는 것은 간단합니다. (Learning Perl에서)
Scott Weaver

299

쉘에서 sed를 사용하여 HTML 을 구문 분석 할 수 있습니다 .

  1. Turing.sed
  2. HTML 파서 작성 (숙제)
  3. ???
  4. 이익!

관련 (정규식 일치를 사용하지 않아야하는 이유) :


3
@kenorb, 당신이 농담을하지 않은 것을 두려워합니다. 질문과 수락 된 답변을 한 번 더 읽으십시오. 이것은 일반적으로 HTML 구문 분석 도구 나 HTML 구문 분석 쉘 도구가 아니라 정규식을 통해 HTML을 구문 분석하는 것입니다.
Palec

1
아니요, @Abdul. 완전히, 아마도 (수학적으로) 불가능합니다.
Palec

3
예, 그 대답은 @Abdul입니다. 그러나 정규식 구현은 수학적 의미에서 실제로 정규 표현식 이 아니며 , 더 강하고 종종 Turing-complete (Type 0 문법과 동일)하게 만드는 구문을 가지고 있습니다. 논쟁은이 사실과 상충되지만, 정규 표현식이 그런 일을 할 수는 없다는 의미에서 여전히 어느 정도 유효하다.
Palec

2
그리고 내가 언급 한 농담은 kenorb (라디칼) 편집, 특히 개정 4, @Abdul 이전 에이 답변의 내용이었습니다.
Palec

3
재미있는 점은 OP가 정규식을 사용하여 HTML을 구문 분석하도록 요청하지 않았다는 것입니다. 그는 정규 표현식을 사용하여 텍스트 (HTML 인 경우)를 일치 시키도록 요청했습니다. 어느 것이 합리적입니까?
Paralife

274

XML과 특히 HTML 을 구문 분석하는 올바른 도구 는 정규식 엔진이 아니라 파서 라는 데 동의합니다 . 그러나 다른 사람들이 지적했듯이 때로는 정규식을 사용하는 것이 더 빠르고 쉽고 데이터 형식을 알고 있으면 작업을 수행합니다.

Microsoft는 실제로 .NET Framework의 정규 표현식에 대한 모범 사례 섹션을 보유하고 있으며 특히 입력 소스 고려에 대해 설명 합니다 .

정규식에는 제한이 있지만 다음을 고려 했습니까?

.NET 프레임 워크는 Balancing Group Definitions를 지원한다는 점에서 정규식에있어 고유합니다 .

이러한 이유로 정규 표현식을 사용하여 XML을 구문 분석 할 수 있다고 생각합니다. 그러나 유효한 XML이어야합니다 ( 브라우저는 HTML을 매우 용서하고 HTML 내부에서 잘못된 XML 구문을 허용합니다 ). "밸런싱 그룹 정의"를 통해 정규 표현식 엔진이 PDA로 작동 할 수 있기 때문에 가능합니다.

위에서 인용 한 기사 1의 인용문 :

.NET 정규식 엔진

상술 한 바와 같이, 적절히 균형 잡힌 구성은 정규식으로 기술 될 수 없다. 그러나 .NET 정규식 엔진은 균형 잡힌 구문을 인식 할 수있는 몇 가지 구문을 제공합니다.

  • (?<group>) -이름 그룹이있는 캡처 스택에서 캡처 된 결과를 푸시합니다.
  • (?<-group>) -캡처 그룹에서 이름 그룹과 함께 가장 많이 캡처합니다.
  • (?(group)yes|no) -이름 그룹이있는 그룹이 있으면 예 부분과 일치하고 그렇지 않으면 부분과 일치하지 않습니다.

이러한 구성을 통해 .NET 정규식을 통해 간단한 버전의 스택 작업 (푸시, 팝 및 빈)을 기본적으로 허용함으로써 제한된 PDA를 에뮬레이션 할 수 있습니다. 간단한 작업은 각각 증가, 감소 및 0과 비교하는 것과 거의 같습니다. 이를 통해 .NET 정규식 엔진은 컨텍스트가없는 언어의 하위 집합, 특히 간단한 카운터 만 필요한 언어를 인식 할 수 있습니다. 결과적으로 비 전통적인 .NET 정규 표현식이 적절히 균형 잡힌 개별 구성을 인식 할 수 있습니다.

다음 정규식을 고려하십시오.

(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
   <!-- .*? -->                  |
   <[^>]*/>                      |
   (?<opentag><(?!/)[^>]*[^/]>)  |
   (?<-opentag></[^>]*[^/]>)     |
   [^<>]*
)*
(?(opentag)(?!))

플래그를 사용하십시오.

  • 한 줄
  • 패턴 공백 무시 (정규 표현식을 축소하고 모든 공백을 제거하는 경우 필요하지 않음)
  • 케이스 무시 (필요하지 않음)

정규식 설명 (인라인)

(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?>                                        # atomic group / don't backtrack (faster)
   <!-- .*? -->                 |          # match xml / html comment
   <[^>]*/>                     |          # self closing tag
   (?<opentag><(?!/)[^>]*[^/]>) |          # push opening xml tag
   (?<-opentag></[^>]*[^/]>)    |          # pop closing xml tag
   [^<>]*                                  # something between tags
)*                                         # match as many xml tags as possible
(?(opentag)(?!))                           # ensure no 'opentag' groups are on stack

A Better .NET Regular Expression Tester 에서 시도해 볼 수 있습니다 .

샘플 소스를 사용했습니다.

<html>
<body>
<div>
   <br />
   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>
</div>
</body>
</html>

이것은 일치하는 것을 발견했습니다 :

   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>

실제로 다음과 같이 나왔습니다.

<ul id="matchMe" type="square">           <li>stuff...</li>           <li>more stuff</li>           <li>               <div>                    <span>still more</span>                    <ul>                         <li>Another &gt;ul&lt;, oh my!</li>                         <li>...</li>                    </ul>               </div>           </li>        </ul>

마지막으로 Jeff Atwood의 기사 : Parsing Html The Cthulhu Way를 즐겼습니다 . 재밌게도 현재 4k 이상 투표 한이 질문에 대한 답변을 인용합니다.


18
System.TextC #의 일부가 아닙니다. .NET의 일부입니다.
John Saunders

8
당신의 정규식 (의 첫 번째 줄에서 (?=<ul\s*id="matchMe"\s*type="square"\s*>) # match start with <ul id="matchMe"...), "UL <"사이와 "ID"해야 \s+하지, \s*) 당신이 <ulid = ...와 일치하지 않으려면,
C0deH4cker

@ C0deH4cker 맞습니다 . \s+대신 식이 있어야합니다 \s*.
Sam

4
나는 그것을 정말로 이해하지는 않지만 정규 표현식이 실패한다고 생각합니다.<img src="images/pic.jpg" />
Scheintod

3
@Scheintod 댓글 주셔서 감사합니다. 코드를 업데이트했습니다. /어딘가에 <img src="images/pic.jpg" />HTML에 실패한 자체 닫는 태그에 대해 이전 표현식이 실패했습니다 .
Sam

258

PHP에서 XML과 HTML을 구문 분석하기 위해 QueryPath 를 사용하는 것이 좋습니다 . 기본적으로 jQuery와 거의 동일한 구문이며 서버 측에만 있습니다.


8
@ Kyle—jQuery는 XML을 구문 분석하지 않고 클라이언트의 내장 구문 분석기 (있는 경우)를 사용합니다. 따라서 jQuery가 필요하지 않지만 두 줄의 일반 오래된 JavaScript가 필요 합니다. 내장 파서가 없으면 jQuery가 도움이되지 않습니다.
RobG

1
@RobG 실제로 jQuery는 내장 파서가 아닌 DOM을 사용합니다.
Qix-MONICA가

11
@ Qix— 문서 작성자에게 " jQuery.parseXML은 브라우저의 기본 구문 분석 기능을 사용합니다 . 출처 : jQuery.parseXML ()
RobG

6
meme 질문 ( meta.stackexchange.com/questions/19478/the-many-memes-of-meta/… ) 에서 왔으므로 답변 중 하나는 'jQuery 사용'
Jorn

221

정규 표현식으로 HTML을 구문 분석 할 수없는 대답은 정확하지만 여기에는 적용되지 않습니다. OP는 단지 하나의 HTML 태그를 정규 표현식으로 구문 분석하고 싶어하며 정규 표현식으로 수행 할 수 있습니다.

그러나 제안 된 정규 표현식은 잘못되었습니다.

<([a-z]+) *[^/]*?>

당신이 되돌아가, 정규식에 무언가를 추가하는 경우처럼 어리석은 일을 일치하도록 강제 할 수있다 <a >>, [^/]너무 관대하다. 또한 공백과 일치 할 수 있으므로 <space>*[^/]*중복 [^/]*됩니다.

내 제안은

<([a-z]+)[^>]*(?<!/)>

(?<! ... )부정적인 룩 비하인드 (Perl regexs)는 어디에 있습니까 ? ", <, 단어, 그리고>가 아닌 모든 것을 읽습니다. 마지막은 /가 아닐 수 있습니다.>".

이것은 <a/ >(정규 정규식과 같은) 것을 허용 하므로,보다 제한적인 것을 원한다면 속성 쌍을 공백으로 구분하여 일치시키는 정규식을 작성해야합니다.


29
질문이 전체 (X) HTML을 구문 분석하는 것이 아니라 (X) HTML 열린 태그를 일치시키는 것에 관한 것입니다.
LarsH

10
대부분의 대답은 무시하는 것처럼 보입니다 .HTML 파서는 HTML 부분에 대한 구현에서 정규 표현식을 잘 사용할 수 있으며 대부분의 파서가 이것을하지 않으면 놀랄 것입니다.
Thayne

@Thayne 정확합니다. 개별 태그를 구문 분석 할 때 정규식이 작업에 적합한 도구입니다. 합리적인 답변을 찾기 위해 페이지를 반쯤 스크롤해야한다는 것은 우스운 일입니다. lexing과 parsing을 혼합하여 허용되는 대답이 올바르지 않습니다.
kasperd

2
속성 값에 '>'또는 '/'문자가 포함되어 있으면 여기에 주어진 대답이 실패합니다.
Martin L

주석 또는 CData 섹션이 포함 된 HTML에서는 제대로 작동하지 않습니다. 따옴표로 묶은 속성에 >문자 가 포함되어 있으면 올바르게 작동하지 않습니다 . 나는 정규 표현식으로 OP가 제안 할 수 있는 것에 동의 하지만 여기에 제시 된 것은 간단합니다.
JacquesB

183

시험:

<([^\s]+)(\s[^>]*?)?(?<!/)>

그것은 당신과 비슷하지만 마지막 >은 슬래시 이후가 아니어야하며 또한 받아들 h1입니다.


107
<a href="foo" title="5> 3 "> 아차 </a>에
가레스

21
그것은 매우 사실이며, 나는 그것에 대해 생각했지만, >심볼이 & gt;
Kobi

65
>속성 값에서 유효합니다. 실제로 '표준 XML'직렬화에서는을 사용하지 않아야합니다 &gt;. ( >속성 값에서 전혀 특이한 것이 아니라는 점을 강조하는 것을 제외하고는 전적으로 관련성 이 없습니다.)
bobince

5
@ Kobi : 느낌표 (끝에 tpward를 넣은 느낌표)는 정규 표현식에서 무엇을 의미합니까?
Marco Demaio

6
@bobince : 확실합니까? 나는 더 이상 이해하지 못 <div title="this tag is a <div></div>">hello</div>
하므로이

179

고대 중국의 전략가, 총장, 철학자 인 Sun Tzu는 다음과 같이 말했습니다.

적을 알고 자신을 알면 한 번의 손실없이 백 번의 전투에서 승리 할 수 ​​있습니다. 자신 만 알지만 상대방은 알지 못하면이기거나 잃을 수 있습니다. 자신이나 적을 모른다면 항상 자신을 위험에 빠뜨릴 것입니다.

이 경우, 당신의 적이 HTML이고 당신은 자신이거나 정규식입니다. 불규칙한 정규 표현식으로 Perl 일 수도 있습니다. HTML을 알아라. 너 자신을 알라.

HTML의 특성을 설명하는 하이쿠를 구성했습니다.

HTML has
complexity exceeding
regular language.

나는 또한 Perl에서 정규 표현식의 특성을 설명하는 haiku를 구성했습니다.

The regex you seek
is defined within the phrase
<([a-zA-Z]+)(?:[^>]*[^/]*)?>

153
<?php
$selfClosing = explode(',', 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed');

$html = '
<p><a href="#">foo</a></p>
<hr/>
<br/>
<div>name</div>';

$dom = new DOMDocument();
$dom->loadHTML($html);
$els = $dom->getElementsByTagName('*');
foreach ( $els as $el ) {
    $nodeName = strtolower($el->nodeName);
    if ( !in_array( $nodeName, $selfClosing ) ) {
        var_dump( $nodeName );
    }
}

산출:

string(4) "html"
string(4) "body"
string(1) "p"
string(1) "a"
string(3) "div"

기본적으로 자체 종료 인 요소 노드 이름을 정의하고 전체 html 문자열을 DOM 라이브러리에로드하고 모든 요소를 ​​잡고 자체 종료되지 않은 요소를 반복하여 필터링하여 작동시킵니다.

나는 당신이 이미이 목적으로 정규식을 사용해서는 안된다는 것을 이미 알고 있다고 확신합니다.


1
실제 XHTML을 다루는 경우 getElementsByTagName을 추가 NS하고 네임 스페이스를 지정하십시오.
meder omuraliev

148

나는 이것이 당신의 정확한 필요성을 모르지만 .NET을 사용하고 있다면 Html Agility Pack 을 사용할 수 없습니까?

발췌 :

"웹 외부"HTML 파일을 구문 분석 할 수있는 .NET 코드 라이브러리입니다. 파서는 "실제"형식의 HTML에 매우 관대합니다.


137

첫 번째 >앞에 a를 원하지 않습니다 /. 봐 여기에 그 작업을 수행하는 방법에 대한 자세한 내용은. 이를 부정적인 lookbehind라고합니다.

그러나 순진한 구현은 <bar/></foo>이 예제 문서에서 일치하게 됩니다.

<foo><bar/></foo>

해결하려는 문제에 대한 정보를 조금 더 제공 할 수 있습니까? 프로그래밍 방식으로 태그를 반복하고 있습니까?


1
그렇습니다. 현재 열려있는 모든 태그를 확인한 다음 별도의 배열에서 닫힌 태그와 비교합니다. RegEx는 뇌를 아프게합니다.
Jeff

122

W3C는 의사 정규 표현식 형식으로 구문 분석하는 방법을 설명합니다.
W3C 링크

의 var에 링크를 따라 QName, S그리고 Attribute선명한 사진을 얻을 수 있습니다.
이를 바탕으로 태그 제거와 같은 것을 처리하기 위해 아주 좋은 정규 표현식을 만들 수 있습니다.


5
이것은 psuedo regexp 형식이 아니며 여기에 지정된 EBNF 형식입니다. XML 사양, 부록 6
Rob G

106

PHP에 필요한 경우 :

PHP DOM의 기능이 제대로 XML 포맷하지 않으면 제대로 작동하지 않습니다. 그들이 인류를 위해 얼마나 더 잘 사용하든 상관없이.

simplehtmldom 은 좋지만 약간의 버그가 있음을 발견했으며 메모리가 매우 큽니다. [큰 페이지에서 충돌이 발생합니다.]

나는 querypath를 사용한 적이 없으므로 그 유용성에 대해 언급 할 수 없다.

시도해야 할 또 다른 방법은 DOMParser 로 리소스가 매우 적으며 한동안 행복하게 사용하고 있습니다. 배우기 쉽고 강력합니다.

파이썬과 자바의 경우 비슷한 링크가 게시되었습니다.

downvoters-XML 파서가 실제 사용을 견딜 수없는 것으로 판명되었을 때만 수업을 썼습니다. 종교적 다운 보팅은 유용한 답변이 게시되는 것을 방지합니다. 질문의 관점에서 사물을 유지하십시오.


95

해결책은 다음과 같습니다.

<?php
// here's the pattern:
$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*(\/>|>)/';

// a string to parse:
$string = 'Hello, try clicking <a href="#paragraph">here</a>
    <br/>and check out.<hr />
    <h2>title</h2>
    <a name ="paragraph" rel= "I\'m an anchor"></a>
    Fine, <span title=\'highlight the "punch"\'>thanks<span>.
    <div class = "clear"></div>
    <br>';

// let's get the occurrences:
preg_match_all($pattern, $string, $matches, PREG_PATTERN_ORDER);

// print the result:
print_r($matches[0]);
?>

깊이 테스트하기 위해 다음과 같이 문자열 자동 닫기 태그를 입력했습니다.

  1. <시간 />
  2. <br/>
  3. <br>

나는 또한 태그를 입력했다 :

  1. 하나의 속성
  2. 둘 이상의 속성
  3. 작은 따옴표큰 따옴표 로 묶인 값
  4. 분리 문자가 큰 따옴표 인 경우 작은 따옴표를 포함하는 속성
  5. "="기호 앞뒤에 공백이있는 "정확하지 않은"속성.

위의 개념 증명에서 작동하지 않는 것을 찾으면 코드를 분석하여 기술을 향상시킬 수 있습니다.

<EDIT> 사용자의 질문은 자체 닫는 태그의 구문 분석을 피하는 것임을 잊었습니다. 이 경우 패턴이 더 단순하여 다음과 같이 바뀝니다.

$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*>/';

@ridgerunner 사용자는 패턴이 인용되지 않은 속성 이나 값이없는 속성을 허용하지 않음을 알았습니다 . 이 경우 미세 조정하면 다음과 같은 패턴이 나타납니다.

$pattern = '/<(\w+)(\s+(\w+)(\s*\=\s*(\'|"|)(.*?)\\5\s*)?)*\s*>/';

</ EDIT>

패턴 이해

누군가 패턴에 대해 더 배우고 싶다면 다음과 같은 줄을 제공합니다.

  1. 첫 번째 하위 표현식 (\ w +)은 태그 이름과 일치합니다.
  2. 두 번째 하위 표현식에는 속성 패턴이 포함됩니다. 다음과 같이 구성됩니다.
    1. 하나 이상의 공백 \ s +
    2. 속성의 이름 (\ w +)
    3. 0 개 이상의 공백 문자 \ s * (여기서 공백을 남겨 둘 수 있음)
    4. "="기호
    5. 다시, 0 개 이상의 공백
    6. 속성 값의 구분 기호, 작은 따옴표 또는 큰 따옴표 ( '| "). 패턴에서 작은 따옴표는 PHP 문자열 구분 기호와 일치하기 때문에 이스케이프 처리됩니다.이 하위 표현식은 괄호로 묶여 참조 될 수 있습니다. 속성의 클로저를 다시 파싱하기 위해서는 이것이 매우 중요한 이유입니다.
    7. 거의 모든 것과 일치하는 속성 값 : (. *?); 이 특정 구문에서 욕심 일치 (별표 뒤에 물음표)를 사용하여 RegExp 엔진은 "미리보기"와 유사한 연산자를 사용하여이 하위 표현식 뒤에 오는 것 외에는 아무것도 일치하지 않습니다.
    8. \ 4 부분은 역 참조 연산자로 , 패턴에서 이전에 정의 된 하위 표현식을 참조합니다.이 경우에는 첫 번째 속성 구분 기호 인 네 번째 하위 표현식을 참조합니다.
    9. 0 개 이상의 공백 \ s *
    10. 속성 하위 표현식은 별표로 제공되는 0 개 이상의 가능한 발생을 지정하여 여기서 끝납니다.
  3. 그런 다음 태그가 ">"기호 앞에 공백으로 끝나기 때문에 0 개 이상의 공백이 \ s * 하위 패턴과 일치합니다.
  4. 일치하는 태그는 간단한 ">"기호 또는 슬래시 (// ||>)를 사용하는 XHTML 클로저로 끝날 수 있습니다. 물론 슬래시는 정규식 구분 기호와 일치하기 때문에 이스케이프 처리됩니다.

작은 팁 :이 코드를 더 잘 분석하려면 HTML 특수 문자 이스케이프를 제공하지 않았기 때문에 생성 된 소스 코드를 살펴볼 필요가 있습니다.


12
값이없는 속성이있는 유효한 태그 (예 :)와 일치하지 않습니다 <option selected>. 또한 인용되지 않은 속성 값이있는 유효한 태그 (예 :)와 일치하지 않습니다 <p id=10>.
ridgerunner

1
@ridgerunner : 귀하의 의견에 감사드립니다. 이 경우 패턴이 약간 변경되어야합니다. $ pattern = '/ <(\ w +) (\ s + (\ w +) (\ s * \ = \ s * (\'| "|) (. *?) \\ 5 \ s *)?) * \ s *> / '; 테스트 한 후 인용되지 않은 속성이나 값이없는 속성의 경우 작동합니다
Emanuele Del Grande

태그 이름 앞의 공백은 어떻습니까? < a href="http://wtf.org" >합법적이라고 확신하지만 일치하지 않습니다.
Floris

7
죄송합니다. 태그 이름 앞의 공백은 불법입니다. "꽤 확신"하는 것 외에는 왜 이의에 대한 증거를 제공하지 않습니까? 다음은 XML 1.1을 참조하는 w3.org/TR/xml11/#sec-starttags 입니다. 테스트를 수행하면 W3C 유효성 검사에서도 경고하므로 HTML 4, 5 및 XHTML에 대해 동일한 내용을 찾을 수 있습니다. 여기 주변의 많은 블라 블라 시인으로서, 나는 대답에 수백 마이너스를 제외하고 는 질문에 명시된 계약 규칙에 따라 코드가 어디에서 실패하는지 입증하기 위해 지능적인 논쟁을받지 못했습니다 . 나는 그들을 환영합니다.
Emanuele Del Grande

@ridgerunner 물론 귀하의 의견은 지능적이고 환영했습니다.
Emanuele Del Grande

91

HTML 문서에서 무언가를 빨리 추출해야 할 때마다 Tidy를 사용하여 XML로 변환 한 다음 XPath 또는 XSLT를 사용하여 필요한 것을 얻습니다. 귀하의 경우 다음과 같은 것 :

//p/a[@href='foo']

89

전에는 HTMLParser 라는 오픈 소스 도구를 사용했습니다 . 다양한 방식으로 HTML을 구문 분석하고 목적을 잘 수행하도록 설계되었습니다. HTML을 다른 트리 노드로 구문 분석 할 수 있으며 API를 사용하여 노드에서 속성을 쉽게 가져올 수 있습니다. 그것을 확인하고 이것이 당신을 도울 수 있는지 확인하십시오.


84

정규식으로 HTML을 구문 분석하고 싶습니다. 의도적으로 손상된 바보 HTML을 구문 분석하지 않습니다. 이 코드는 내 주요 파서입니다 (Perl 에디션).

$_ = join "",<STDIN>; tr/\n\r \t/ /s; s/</\n</g; s/>/>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print

htmlsplit이라고하며 HTML을 한 줄로 나누고 각 줄에 하나의 태그 또는 텍스트 덩어리를 만듭니다. 그런 다음 grep , sed , Perl 등과 같은 다른 텍스트 도구 및 스크립트를 사용하여 행을 추가로 처리 할 수 ​​있습니다 . 농담조차하지 않습니다. :) 즐기십시오.

거대한 웹 페이지를 처리하고 싶다면 내 slurp-everything-first Perl 스크립트를 멋진 스트리밍으로 재구성하는 것이 간단합니다. 그러나 실제로는 필요하지 않습니다.

나는 이것에 대해 downvoted 얻을 것 내기.

HTML 분할


내 기대에 반하여 이것은 약간의 찬성을 얻었으므로 더 나은 정규 표현식을 제안 할 것입니다.

/(<.*?>|[^<]+)\s*/g    # get tags and text
/(\w+)="(.*?)"/g       # get attibutes

XML / XHTML에 좋습니다.

약간의 변형으로 지저분한 HTML에 대처하거나 HTML-> XHTML을 먼저 변환 할 수 있습니다.


정규 표현식을 작성하는 가장 좋은 방법 은 불투명 한 한 줄짜리 또는 주석이 달린 다중 행 괴물이 아닌 Lex / Yacc 스타일입니다. 아직 여기서는하지 않았습니다. 이것들은 간신히 필요합니다.


35
"고의로 손상된 바보 HTML을 구문 분석하지 않습니다." 코드에서 차이점을 어떻게 알 수 있습니까?
케빈 판코

HTML이 깨 졌는지 여부는 중요하지 않습니다. 그 일은 여전히 ​​HTML을 태그와 텍스트로 나눕니다. 사람들이 텍스트 나 속성에 이스케이프 처리되지 않은 <또는> 문자를 포함시키는 경우에만 문제가 될 수 있습니다. 실제로 작은 HTML 스플리터가 잘 작동합니다. 휴리스틱으로 가득 찬 거대한 괴물이 필요하지 않습니다. 간단한 솔루션은 모든 사람을위한 것이 아닙니다 ...!
Sam Watkins

XML / XHTML에 대한 태그, 텍스트 및 속성을 추출하기 위해 더 간단한 정규 표현식을 추가했습니다.
Sam Watkins

(속성 버그 1 얻기) /(\w+)="(.*?)"/는 큰 따옴표를 가정합니다. 작은 따옴표로 값을 그리워합니다. html 버전 4 이하에서는 간단한 단어 인 경우 인용되지 않은 값이 허용됩니다.
David Andersson

(속성 버그 2 가져 오기) /(\w+)="(.*?)"/는 속성 내에서 속성처럼 보이는 텍스트와 잘못 일치 할 수 있습니다 (예 :) <img title="Nope down='up' for aussies" src="..." />. 전 세계에 적용되는 경우 일반 텍스트 또는 html 주석의 해당 항목과도 ​​일치합니다.
David Andersson

74

다음은 불경건 한 정규 표현식을 사용하여 HTML을 구문 분석 하는 PHP 기반 파서 입니다. 이 프로젝트의 저자로서 정규 표현식으로 HTML을 구문 분석 할 수는 있지만 효율적이지 않다는 것을 알 수 있습니다. wp-Typography WordPress 플러그인에서 와 같이 서버 측 솔루션이 필요한 경우 작동합니다.


1
htmlawed 는 필터링, 변환 등을 위해 HTML을 구문 분석하는 또 다른 PHP 프로젝트입니다. 알아낼 수 있으면 좋은 코드가 있습니다!
user594694 2016 년

아니요 . 정규식으로 HTML을 구문 분석 할 수 없습니다 . 그러나 일부 하위 집합의 경우 작동 할 있습니다.
mirabilos

71

여기에 HTML을 BBCode로 대체하는 멋진 정규식이 있습니다 . 네이저 사람들 모두 HTML을 완전히 파싱하지 않고 위생적으로 처리하려고 시도한다는 점에 유의하십시오. 그는 자신의 간단한 "파서"가 이해할 수없는 태그를 제거 할 여유가 있습니다.

예를 들면 다음과 같습니다.

$store =~ s/http:/http:\/\//gi;
$store =~ s/https:/https:\/\//gi;
$baseurl = $store;

if (!$query->param("ascii")) {
    $html =~ s/\s\s+/\n/gi;
    $html =~ s/<pre(.*?)>(.*?)<\/pre>/\[code]$2\[\/code]/sgmi;
}

$html =~ s/\n//gi;
$html =~ s/\r\r//gi;
$html =~ s/$baseurl//gi;
$html =~ s/<h[1-7](.*?)>(.*?)<\/h[1-7]>/\n\[b]$2\[\/b]\n/sgmi;
$html =~ s/<p>/\n\n/gi;
$html =~ s/<br(.*?)>/\n/gi;
$html =~ s/<textarea(.*?)>(.*?)<\/textarea>/\[code]$2\[\/code]/sgmi;
$html =~ s/<b>(.*?)<\/b>/\[b]$1\[\/b]/gi;
$html =~ s/<i>(.*?)<\/i>/\[i]$1\[\/i]/gi;
$html =~ s/<u>(.*?)<\/u>/\[u]$1\[\/u]/gi;
$html =~ s/<em>(.*?)<\/em>/\[i]$1\[\/i]/gi;
$html =~ s/<strong>(.*?)<\/strong>/\[b]$1\[\/b]/gi;
$html =~ s/<cite>(.*?)<\/cite>/\[i]$1\[\/i]/gi;
$html =~ s/<font color="(.*?)">(.*?)<\/font>/\[color=$1]$2\[\/color]/sgmi;
$html =~ s/<font color=(.*?)>(.*?)<\/font>/\[color=$1]$2\[\/color]/sgmi;
$html =~ s/<link(.*?)>//gi;
$html =~ s/<li(.*?)>(.*?)<\/li>/\[\*]$2/gi;
$html =~ s/<ul(.*?)>/\[list]/gi;
$html =~ s/<\/ul>/\[\/list]/gi;
$html =~ s/<div>/\n/gi;
$html =~ s/<\/div>/\n/gi;
$html =~ s/<td(.*?)>/ /gi;
$html =~ s/<tr(.*?)>/\n/gi;

$html =~ s/<img(.*?)src="(.*?)"(.*?)>/\[img]$baseurl\/$2\[\/img]/gi;
$html =~ s/<a(.*?)href="(.*?)"(.*?)>(.*?)<\/a>/\[url=$baseurl\/$2]$4\[\/url]/gi;
$html =~ s/\[url=$baseurl\/http:\/\/(.*?)](.*?)\[\/url]/\[url=http:\/\/$1]$2\[\/url]/gi;
$html =~ s/\[img]$baseurl\/http:\/\/(.*?)\[\/img]/\[img]http:\/\/$1\[\/img]/gi;

$html =~ s/<head>(.*?)<\/head>//sgmi;
$html =~ s/<object>(.*?)<\/object>//sgmi;
$html =~ s/<script(.*?)>(.*?)<\/script>//sgmi;
$html =~ s/<style(.*?)>(.*?)<\/style>//sgmi;
$html =~ s/<title>(.*?)<\/title>//sgmi;
$html =~ s/<!--(.*?)-->/\n/sgmi;

$html =~ s/\/\//\//gi;
$html =~ s/http:\//http:\/\//gi;
$html =~ s/https:\//https:\/\//gi;

$html =~ s/<(?:[^>'"]*|(['"]).*?\1)*>//gsi;
$html =~ s/\r\r//gi;
$html =~ s/\[img]\//\[img]/gi;
$html =~ s/\[url=\//\[url=/gi;

15
이러지 마 부디.
maletor

68

(x) HTML을 구문 분석하는 RegExp 메소드의 질문에 대해, 일부 한계에 대해 이야기 한 모든 사람들에 대한 대답은 다음과 같습니다 . 여기서 NOBODY재귀 에 대해 말했기 때문에이 강력한 무기의 힘을 지배 할만큼 훈련되지 않았습니다 .

RegExp에 구애받지 않는 동료가이 토론에 대해 알 렸습니다.이 토론은 웹에서이 오래되고 인기있는 주제에 대해 처음은 아닙니다.

일부 게시물을 읽은 후, 내가 한 첫 번째 일은이 스레드에서 "? R"문자열을 찾는 것입니다. 두 번째는 "재귀"를 검색하는 것이 었습니다.
아니, 성스러운 소, 일치하는 것이 없습니다.
파서가 구축 된 주요 메커니즘을 아무도 언급하지 않았기 때문에 나는 아무도 그 요점을 알지 못한다는 것을 곧 알게되었다.

(x) HTML 파서가 재귀를 필요로하는 경우, 재귀없는 RegExp 파서는 목적에 충분하지 않습니다. 간단한 구조입니다.

RegExp검은 예술은 마스터하기가 어렵 기 때문에 개인 웹 전체를 한 손으로 캡처하기 위해 개인 솔루션을 테스트하고 테스트하는 동안 남은 가능성이 더 있습니다 ... 글쎄, 나는 그것에 대해 확신합니다 :)

마술 패턴은 다음과 같습니다.

$pattern = "/<([\w]+)([^>]*?)(([\s]*\/>)|(>((([^<]*?|<\!\-\-.*?\-\->)|(?R))*)<\/\\1[\s]*>))/s";

먹어봐.
PHP 문자열로 작성되므로 "s"수정자는 클래스에 개행을 포함시킵니다.
다음 은 1 월에 작성한 PHP 매뉴얼에 대한 샘플 참고 사항입니다.

(주의 사항에 따르면 "m"수정자를 잘못 사용했습니다. ^ 또는 $ 앵커리지가 사용되지 않았기 때문에 RegExp 엔진에 의해 버려지더라도 지워 져야합니다).

이제이 방법의 한계에 대해 더 많은 정보를 얻을 수 있습니다.

  1. RegExp 엔진의 특정 구현에 따르면 재귀에는 구문 분석 된 중첩 패턴수가 제한 될 수 있지만 사용되는 언어에 따라 다릅니다.
  2. 손상된 (x) HTML이 심각한 오류를 일으키지 않지만 위생 상태가 아닙니다 .

어쨌든 그것은 단지 RegExp 패턴 일 뿐이지 만, 많은 강력한 구현을 개발할 가능성을 밝힙니다.
필자는이 패턴을 작성하여 프레임 워크에 구축 한 템플릿 엔진 의 재귀 강하 파서 를 강화했으며 , 실행 시간이나 메모리 사용량 (동일한 구문을 사용하는 다른 템플릿 엔진과는 상관 없음)에서 성능이 정말 뛰어납니다.


35
이것을 "속성보다 더 큰 것을 허용하지 않는 정규식"저장소에 넣겠습니다. <input value = "is 5> 3?"과 비교하여 확인하십시오. />
Gareth

68
프로덕션 코드에 이와 같은 것을 넣으면 관리자가 총에 맞을 것입니다. 배심원은 결코 그를 유죄 판결을 내리지 않았습니다.
aehiilrs

30
정규 표현식은 재귀 적이 지 않기 때문에 작동하지 않습니다. 정규 표현식에 재귀 연산자를 추가하면 기본적으로 구문이 더 나쁜 CFG 만 만들어집니다. 불필요한 기능으로 이미 넘쳐나는 것에 재귀를 심하게 삽입하기보다는 처음에 재귀 적으로 설계된 것을 사용하지 않겠습니까?
Welbog

16
내 이의 제기는 투자 한 기능 중 하나가 아닙니다. RegEx의 문제점은 cutsey에 하나의 라이너를 게시 할 때보다 효율적으로 무언가를 수행 한 것 같습니다 ( "한 줄의 코드 참조"). 물론 아무도 자신의 치트 시트와 함께 보낸 반 시간 (또는 3)을 언급하지 않으며 가능한 모든 입력 순열을 테스트합니다. 그리고 일단 관리자가 코드를 알아 내거나 유효성을 검사 할 때 모든 것을지나 치면 코드를보고 올바른지 확인할 수 없습니다. 표현을 해부하고 본질적으로 다시 한번 다시 테스트해야합니다 ...
Oorang

15
... 좋다는 것을 아는 것. 그리고 그것은 정규 표현식에 능숙한 사람들에게도 일어날 것입니다 . 그리고 솔직히 말해서 압도적 인 대다수의 사람들이 그것을 잘 알지 못할 것이라고 생각합니다. 그래서 당신은 가장 악명 높은 유지 보수 악몽 중 하나를 가져 와서 다른 유지 보수 악몽 인 재귀와 결합하고 내 프로젝트에서 실제로 필요한 것은 조금 덜 영리한 사람이라고 생각합니다. 목표는 나쁜 프로그래머가 코드 기반을 어 기지 않고 유지할 수있는 코드를 작성하는 것입니다. 나는 그것이 가장 일반적인 분모로 코딩하는 것을 좋아합니다. 그러나 우수한 인재를 고용하는 것은 어렵고 종종…
Oorang

62

많은 사람들이 이미 지적했듯이 HTML은 일반 언어가 아니기 때문에 구문 분석이 매우 어렵습니다. 이것에 대한 나의 해결책은 깔끔한 프로그램을 사용하여 일반 언어로 바꾸고 XML 파서를 사용하여 결과를 소비하는 것입니다. 이에 대한 좋은 옵션이 많이 있습니다. 내 프로그램은 jtidy 라이브러리 와 함께 Java를 사용 하여 HTML을 XML로 변환 한 다음 Jaxen을 xpath로 결과로 작성합니다.


61
<\s*(\w+)[^/>]*>

부품 설명 :

<: 시작 캐릭터

\s*: 태그 이름 앞에 공백이있을 수 있습니다 (추악하지만 가능).

(\w+): 태그는 문자와 숫자 (h1)를 포함 할 수 있습니다. 글쎄, \w'_'와도 일치하지만 아프지 않습니다. 궁금하다면 ([a-zA-Z0-9] +)를 대신 사용하십시오.

[^/>]*: 닫을 때까지 >/닫을 때까지의 모든 것>

>: 마감 >

관련되지 않은

그리고 정규 표현을 과소 평가하는 동료들에게는 정규 언어만큼 강력하다고 말합니다.

N 개의 BA N BA N 되지 정규이고 심지어 문맥 자유하는 매칭 될 수있다^(a+)b\1b\1$

역 참조 FTW !


@GlitchMr, 그것이 그의 요점이었습니다. 현대의 정규 표현은 기술적으로 정규적이지 않으며 그럴 이유가 없습니다.
alanaktion

3
@alanaktion : "현대"정규식 (읽기 : Perl 확장자)은 O(MN)(M은 정규식 길이, N은 텍스트 길이) 내에서 일치 할 수 없습니다 . 역 참조는 그 원인 중 하나입니다. awk의 구현에는 역 참조가 없으며 O(MN)시간 내에 모든 것을 일치 시킵니다.
Konrad Borowski

56

단순히 구문 분석없이 야심으로 해당 태그를 찾으려면 다음 정규식을 사용하십시오.

/<[^/]*?>/g

나는 그것을 30 초 안에 작성하고 여기에서 테스트했다 : http://gskinner.com/RegExr/

무시하려는 태그 유형은 무시하면서 언급 한 태그 유형과 일치합니다.


2
나는 당신이 \/>대신 의미한다고 생각합니다 \\>.
Justin Morgan

아니요, \>제가 의미하는 바는 그대로 입니다. 원래 게시물의 정규 표현식을 편집하려고하지 않았습니다.
Lonnie Best

2
참고로, 꺾쇠 괄호를 벗어날 필요는 없습니다. 물론, 어쨌든 그들을 피하는 것은 해가되지 않지만 피할 수있는 혼란을보십시오. ;)
Alan Moore

어떤 것이 특별한 성격인지 아닌지 확신 할 수 없을 때 때때로 불필요하게 탈출합니다. 답을 편집했습니다. 그것은 동일하지만 더 간결하게 작동합니다.
Lonnie Best

지금 이것을 보면서, 나는 당신이 왜 생각하는지 생각하지 않습니다 \/. 왜냐하면 그것이 요구 사항과 정확히 반대이기 때문입니다. 네가 네거티브 필터 패턴을 제공한다고 생각했을 수도 있습니다.
저스틴 모건

54

끝에 "/"없이 태그를 일치시키려는 것 같습니다. 이 시도:

<([a-zA-Z][a-zA-Z0-9]*)[^>]*(?<!/)>

8
작동하지 않습니다. 입력 '<xa = "<b>"/> <y>'의 경우, x는 종료되지만 x와 y는 일치합니다.
11

51

프로그래밍을 할 때 HTML을 다룰 때 정규식 대신 전용 파서와 API를 사용하는 것이 가장 좋습니다. 특히 정확성이 가장 중요한 경우 (예 : 처리에 보안 관련 사항이있는 경우)는 사실입니다. 그러나 XML 스타일 마크 업을 정규식으로 처리해서는 안된다는 교리 적 견해에 동의하지 않습니다. 정규식이 텍스트 편집기에서 일회성 편집, 손상된 XML 파일 수정 또는 XML 형식이 아닌 것처럼 보이는 파일 형식 처리와 같은 작업에 유용한 도구 인 경우가 있습니다. 알아야 할 몇 가지 문제가 있지만 극복 할 수 없거나 반드시 관련이없는 것은 아닙니다.

<([^>"']|"[^"]*"|'[^']*')*>방금 언급 한 것과 같은 경우와 같이 간단한 정규 표현식 으로 충분합니다. 그것은 모든 것을 고려한 순진한 솔루션이지만 >속성 값에 인코딩되지 않은 기호를 올바르게 허용 합니다. 예를 들어 table태그를 찾고 있다면로 태그를 조정할 수 있습니다 </?table\b([^>"']|"[^"]*"|'[^']*')*>.

좀 더 "고급"HTML 정규식이 어떻게 보이는지 이해하기 위해 다음은 실제 브라우저 동작과 HTML5 구문 분석 알고리즘을 에뮬레이션하는 상당히 존경스러운 작업입니다.

</?([A-Za-z][^\s>/]*)(?:=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)|[^>])*(?:>|$)

다음은 XML 태그에 허용되는 전체 유니 코드 문자를 설명하지는 않지만 상당히 엄격한 XML 태그 정의와 일치합니다.

<(?:([_:A-Z][-.:\w]*)(?:\s+[_:A-Z][-.:\w]*\s*=\s*(?:"[^"]*"|'[^']*'))*\s*/?|/([_:A-Z][-.:\w]*)\s*)>

물론, 이것들은 주변 상황과 몇 가지 중요한 경우를 설명하지 않지만 실제로 원한다면 (예를 들어, 다른 정규 표현식의 일치 항목을 검색하여) 그러한 것들도 처리 할 수 ​​있습니다.

하루가 끝나면 해당 도구가 정규식 인 경우에도 작업에 가장 적합한 도구를 사용하십시오.


49

그 목적을 위해 정규 표현식을 사용하는 것이 적합하지 않고 효과적이지 않지만 때로는 정규 표현식이 간단한 일치 문제에 대한 빠른 해결책을 제공하며 내 견해로는 사소한 작업에 정규 표현식을 사용하는 것이 무섭지 않습니다.

Steven Levithan이 작성한 가장 안쪽의 HTML 요소를 일치시키는 것에 대한 결정적인 블로그 게시물 이 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.