XML과 HTML을 정규식으로 구문 분석하기 어려운 이유에 대한 몇 가지 예를 제공 할 수 있습니까? [닫은]


402

하나의 실수 나는 사람들이 만드는 참조 이상 과 다시 정규식으로 XML 또는 HTML을 구문 분석을 시도하고 있습니다. XML과 HTML을 파싱하는 것이 어려운 몇 가지 이유는 다음과 같습니다.

사람들은 파일을 일련의 행으로 취급하려고하지만 유효합니다.

<tag
attr="5"
/>

사람들은 <또는 <tag를 태그의 시작으로 취급하기를 원하지만 다음과 같은 것들이 야생에 존재합니다.

<img src="imgtag.gif" alt="<img>" />

사람들은 종종 시작 태그와 끝 태그를 일치 시키려고하지만 XML과 HTML을 사용하면 태그에 자신을 포함시킬 수 있습니다 (전통적인 정규 표현식은 전혀 처리 할 수 ​​없음).

<span id="outer"><span id="inner">foo</span></span> 

사람들은 종종 문서의 내용 (예 : 유명한 "주어진 페이지에서 모든 전화 번호 찾기"문제)과 일치하기를 원하지만 데이터가 표시 될 때 데이터가 표시 될 수 있습니다 (보았을 때 정상으로 보이는 경우에도).

<span class="phonenum">(<span class="area code">703</span>)
<span class="prefix">348</span>-<span class="linenum">3020</span></span>

주석에 형식이 잘못되었거나 불완전한 태그가 포함될 수 있습니다.

<a href="foo">foo</a>
<!-- FIXME:
    <a href="
-->
<a href="bar">bar</a>

다른 어떤 문제를 알고 있습니까?


14
웹 브라우저는 이러한 종류의 혼란을 초당 수백만 번 이해합니다. 누군가가 단순한 필사자를 위해 웹 페이지 파서 클래스를 만들 수 없습니까?
— Jon Winstanley

24
존. Perl에는 많은 HTML :: Parser, HTML :: TreeBuilder 등이 있습니다.
— Chas. Owens

12
가장 좋은 대답은 stackoverflow.com/a/1732454/135078입니다 (Zalgo주의)
— Kelly S. French

3
[정규식으로 [X] HTML을 구문 분석 할 수없는 이유] [1] [1] : stackoverflow.com/a/1732454/468725
— Pavel P

4
여기 당신이 방법의 좋은 설명 확실하게 할 수 있습니다 패턴 구문 분석 HTML 뿐만 아니라, 왜 같은 당신은 아마 그렇게하지 않으려는.
— tchrist

답변:


260

다음은 유용한 XML을 보여줍니다.

<!DOCTYPE x [ <!ENTITY y "a]>b"> ]>
<x>
    <a b="&y;>" />
    <![CDATA[[a>b <a>b <a]]>
    <?x <a> <!-- <b> ?> c --> d
</x>

그리고이 작은 기쁨 묶음은 유효한 HTML입니다.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" [
    <!ENTITY % e "href='hello'">
    <!ENTITY e "<a %e;>">
]>
    <title>x</TITLE>
</head>
    <p id  =  a:b center>
    <span / hello </span>
    &amp<br left>
    <!---- >t<!---> < -->
    &e link </a>
</body>

유효하지 않은 구문에 대한 모든 브라우저 별 구문 분석은 말할 것도 없습니다.

행운을 빕니다.

편집 (Jörg W Mittag) : 다음은 잘 구성된 유효한 HTML 4.01의 또 다른 멋진 부분입니다.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd"> 
<HTML/
  <HEAD/
    <TITLE/>/
    <P/>

6
XML 하나? 거기에 몇 가지 다른 구성이 있는데, 문제가 있습니까? DTD 내부 하위 집합? 그것은 새로운 & 엔터티를 정의하고 있습니다; 일반적으로 따옴표가 아닌 경우 내부 하위 집합을 종료하는 ']>'시퀀스를 포함하는 'y'라고합니다.
— bobince

16
(이것은 DTD 유효성 검사 파서가 아닌 경우에도 문서를 올바르게 구문 분석하기 위해 XML의 좀 더 난해하고 고풍스러운 DTD 기능에 대해 상당히 깊이 알고 있어야 함을 보여줍니다.)
— bobince

17
HTML 예제는 드물게 알려진 기능인 shorttags를 사용합니다. w3.org/QA/2007/10/shorttags.html
— netvope

25
위와 같이 HTML을 작성할 때마다 Tim Berners-Lee는 단 한 번의 눈물을 흘립니다.
— fgysin reinstate Monica

5
"]"의 첫 번째 발생에서 Stackoverflow의 구문 형광펜이 실패하는 방식이 마음에 듭니다.
— GlassGhost

71

사실은

<img src="imgtag.gif" alt="<img>" />

유효한 HTML이 아니며 유효한 XML도 아닙니다.

'<'및 '>'는 속성 문자열 내에서 유효한 문자가 아니므로 유효한 XML이 아닙니다. 해당 XML 엔티티를 사용하여 이스케이프해야합니다. & lt; & gt;

HTML에서 짧은 닫기 양식이 허용되지 않기 때문에 유효한 HTML이 아닙니다 (XML 및 XHTML에서는 정확함). 'img'태그는 HTML 4.01 사양에 따라 암시 적으로 닫힌 태그이기도합니다. 즉, 수동으로 닫는 것은 실제로 잘못되었으며 다른 태그를 두 번 닫는 것과 같습니다.

HTML의 올바른 버전은

<img src="imgtag.gif" alt="&lt;img&gt;">

XHTML과 XML의 올바른 버전은

<img src="imgtag.gif" alt="&lt;img&gt;"/>

다음 예제도 유효하지 않습니다.

<
tag
attr="5"
/>

이것은 유효한 HTML 또는 XML도 아닙니다. 속성과 닫는 '>'는 원하는 위치에있을 수 있지만 태그 이름은 '<'바로 뒤에 있어야합니다. 유효한 XML은 실제로

<tag
attr="5"
/>

그리고 여기 또 하나 더 펑키 한 것이 있습니다 : 실제로 "또는"를 속성 인용 문자로 사용하도록 선택할 수 있습니다

<img src="image.gif" alt='This is single quoted AND valid!'>

게시 된 다른 모든 이유는 정확하지만 HTML 구문 분석의 가장 큰 문제는 사람들이 일반적으로 모든 구문 규칙을 올바르게 이해하지 못한다는 것입니다. 브라우저가 태그를 HTML로 해석한다고해서 실제로 유효한 HTML을 작성한 것은 아닙니다.

편집 : 심지어 stackoverflow.com도 유효하고 유효하지 않은 정의에 대해 동의합니다. 수정 된 버전이있는 동안 잘못된 XML / HTML이 강조 표시되지 않습니다.

기본적으로 XML은 정규 표현식으로 구문 분석되지 않습니다. 그러나 그렇게 할 이유도 없습니다. 각 언어마다 많은 XML 파서가 있습니다. SAX 파서, DOM 파서 및 풀 파서 중에서 선택할 수 있습니다. 이 모든 것이 정규 표현식으로 구문 분석하는 것보다 훨씬 빠르므로 결과 DOM 트리에서 XPath 또는 XSLT와 같은 멋진 기술을 사용할 수 있습니다.

따라서 내 대답은 다음과 같습니다. 정규 표현식으로 XML을 구문 분석하는 것뿐만 아니라 나쁜 생각이기도합니다. 수백만 개의 기존 XML 파서 중 하나를 사용하고 XML의 모든 고급 기능을 활용하십시오.

HTML은 너무 직접 구문 분석을 시도하기가 너무 어렵습니다. 첫째, 법적인 구문에는 당신이 알지 못하는 작은 미묘함이 많이 있으며, 두 번째로, 야생의 HTML은 엄청난 양의 더미입니다 (내가 표류하게됩니다). 태그 수프와 같은 HTML을 잘 처리하는 다양한 lax 파서 라이브러리가 있습니다.이를 사용하십시오.


8
> as>를 벗어날 필요는 없습니다.
— Joey

8
좋아요, s / valid /는 wild / g
— Chas에 있습니다. Owens

1
실제로, 사양에 따라 <as <& and & amp; 속성은 ""& ","& apos; 속성은 그저 많은 파서 일뿐입니다.
— LordOfThePigs

19
사양에서 '>'는 이스케이프해야한다고 말하지 않습니다. 내용에서 '']]> '시퀀스의 특수한 경우는 예외입니다. 이러한 이유로 항상 '>'를 이스케이프하는 것이 가장 쉽지만 사양에는 필요하지 않습니다.
— bobince

8
>기호는 HTML에서 완벽하게 유효 stackoverflow.com/questions/94528/...
— JFS

56

이 주제에 관한 전체 블로그 항목을 작성했습니다 : 정규식 제한

문제의 핵심은 HTML과 XML이 재귀 구조이므로 제대로 구문 분석하기 위해 계산 메커니즘이 필요하다는 것입니다. 진정한 정규 표현식은 계산할 수 없습니다. 계산하려면 컨텍스트 프리 문법이 있어야합니다.

이전 단락에는 약간의 경고가 있습니다. 특정 정규식 구현은 이제 재귀 개념을 지원합니다. 그러나 정규 표현식에 재귀를 추가하기 시작하면 경계가 실제로 확장되고 파서를 고려해야합니다.


20

목록에없는 한 가지는 속성이 어떤 순서로나 나타날 수 있다는 것입니다. 따라서 정규 표현식이 href "foo"및 클래스 "bar"와의 링크를 찾으려면 순서에 관계없이 다른 수를 가질 수 있습니다 그들 사이의 것들.


아, 그렇습니다.이 질문 (첫 번째 링크)을 요구하는 질문조차있었습니다.
— Chas. Owens

16

"구문 분석"의 의미에 따라 다릅니다. 일반적으로 XML 문법은 결코 정규적이지 않기 때문에 정규식을 사용하여 XML을 구문 분석 할 수 없습니다. 간단히 말해서, 정규 표현식은 셀 수 없습니다 (물론, Perl 정규 표현식은 실제로 계산할 수 있습니다).


역 참조가 오픈 태그와 클로즈 태그의 문제를 해결할 수 있다고 생각합니다.
— Rishul Matta

1
@RishulMatta : 어떻게 요? 역 참조 횟수가 제한되어 있으며 태그를 역으로 바꿔야한다는 점에 유의하십시오. 또한 정규식의 엄격한 정의는 역 참조를 허용하지 않습니다.
— Willem Van Onsem 2016 년

.NET은 팝 및 푸시 식의 균형을 조정할 수 있으며 이론적으로 계층 구조를 일치시키는 데 사용할 수 있습니다. 그러나 여전히 나쁜 생각입니다.
— Abel

9

사람들은 실제로 정규 표현식을 사용하여 실수를 저지르고 있습니까? 아니면 그들이 달성하려는 작업에 충분합니까?

다른 사람들이 대답 했으므로 정규식을 사용하여 html 및 xml을 구문 분석 할 수 없다는 것에 전적으로 동의합니다.

그러나 요구 사항이 html / xml을 구문 분석하지 않고 html / xml의 "알려진"비트에서 하나의 작은 비트의 데이터를 얻는 것이라면 정규식 또는 심지어 더 간단한 "하위 문자열"로 충분합니다.


7
"충분히 좋다"고 정의하십시오. 필연적으로 간단한 정규식이 작동하지 않습니다. 버그와 일치하지 않는 것과 일치하지 않습니까? 그렇다면 정규 표현식을 사용하는 것은 실수입니다. HTML 및 XML 파서는 사용하기 어렵지 않습니다. 그것들을 배우지 않는 것은 잘못된 경제입니다.
— Chas. Owens

1
좋아, "충분히 좋은"을 정의하십시오. 클라이언트 IP 주소를 알려주는 웹 페이지가 있다고 가정 해 보겠습니다. 그게 다야. 이제 클라이언트 컴퓨터의 IP 주소를 알려주는 응용 프로그램을 작성해야합니다. 해당 사이트로 이동하여 IP 주소를 찾아서 반환합니다. HTML 파싱이 필요하지 않습니다!
— Robin Day

2
형식을 완전히 제어 할 수있는 임의의 문자열이있는 경우 문자열이 제대로 구성된 XML이라는 사실은 실제로 관련이 없습니다. 그러나 XML의 사용 사례는 실제로이 범주에 속하지 않습니다.
— Robert Rossney

15
나는 고통스런 경험을 통해 터무니없이 복잡한 정규식 패턴을 사용하여 원하는 것을 얻을 수 있다고 대부분 말할 수 있습니다. 웹 사이트가 재미없는 작은 변화를 겪을 때까지이 정규식을 던져서 창 밖으로 이틀 동안 울고 새로 시작할 수 있습니다.
— Thomasz 2009

@Robert : "거의 사용 사례가 없습니다"는 과장된 것입니다. 내 경험에는 일반적으로 충분한 유스 케이스가 있습니다. YAGNI가 여기에 적용됩니다 ... 때때로. 요령은 해결해야 할 특정 작업에 대해 방탄 및 오래 지속되는 솔루션의 필요성을 아는 것입니다. 로빈은 좋은 지적이 있습니다. 그는 완전한 XML 파싱이 항상 그만한 가치가있는 것은 아니라고 말하고 있습니다. 사용 방법을 알고 있더라도 마찬가지입니다.
— LarsH

6

사람들은 일반적으로 욕심 많은 패턴을 쓰는 것을 기본으로 생각하며, 종종 생각할 수없는. * 파일을 대량의 청크를 가능한 가장 큰 <foo>. * </ foo>로 끌어들입니다.


2
와 함께 반복을 게으르게 만드는 것뿐만 아니라 .*?<, 같은 부정 문자 클래스를 사용하여 문제를 해결할 수 [^<]*<있습니다. (면책 조항 : 분명히 그것은 여전히 ​​바보가 아닙니다. 그것은 문제의 핵심입니다.)
— Rory O'Kane

6

나는 "바퀴를 다시 발명하지 말라"고 유혹하고 있습니다. XML은 실제로 매우 복잡한 형식입니다. 아마 "싱크로 트로트 론을 재발 명하지 마십시오"라고 말해야 할 것입니다.

아마도 올바른 진부한 시작은 "당신이 가진 모든 것이 망치 일 때 ..."정규 표현식을 사용하는 방법을 알고 있는데, 정규 표현식은 구문 분석에 능숙합니다. 왜 XML 구문 분석 라이브러리를 배우는 것이 귀찮습니까?

XML 구문 분석이 어렵 기 때문 입니다. XML 파싱 라이브러리를 사용하는 법을 배우지 않아도되는 노력은 많은 창의적인 작업과 버그 해결에 따른 것 이상입니다. 귀하를 위해 Google "XML 라이브러리"를 사용하고 다른 사람의 작업을 활용하십시오.


3
C ++만큼 복잡하지는 않습니다.
— Cole Johnson

6
@Cole "Cole9"Johnson RE를 사용하여 C ++을 구문 분석하지 않습니다.
— 아이작 라 비노 비치

2
XML이 싱크로트론 인 경우 C ++는 Large Hadron Collider입니다.
— Kevin Kostlan

4

나는 이 고전 이 당신이 찾고있는 정보를 가지고 있다고 생각 합니다 . 의견 중 하나에서 요점을 찾을 수 있습니다.

여기에 결함이 있다고 생각합니다. HTML은 Chomsky Type 2 문법 (문맥이없는 문법)이고 RegEx는 Chomsky Type 3 문법 (정규 표현식)입니다. 유형 2 문법은 유형 3 문법보다 근본적으로 복잡하기 때문에이 작업을 수행 할 수는 없습니다 . 그러나 많은 사람들이 시도 할 것이고, 어떤 사람들은 성공을 주장 할 것이고, 다른 사람들은 잘못을 찾아 내고 당신을 완전히 엉망으로 만들 것입니다.

Wikipedia의 더 많은 정보 : Chomsky Hierarchy


6
"정규 표현"은 공식 문법 토론에서 여기와 정확히 같은 의미를 갖지 않습니다. 가장 현존하는 정규식 엔진은 Chomsky Type 3 문법보다 강력합니다 (예 : 욕심없는 매칭, 역 참조). Perl과 같은 일부 정규식 엔진은 Turing이 완료되었습니다. 이것들조차 HTML을 파싱하기에 열악한 도구라는 것은 사실이지만, 종종 언급되는 논쟁은 그 이유가 아닙니다.
— dubiousjim

4

문제는 다음과 같이 요약됩니다.

  1. 정규식은 거의 부정확합니다. 올바르게 일치하지 않는 합법적 인 입력이 있습니다. 충분히 열심히 일하면 99 % 올바르거나 99.999 % 올릴 수 있지만, 엔티티를 사용하여 XML이 허용하는 이상한 것들 때문에 100 % 올바르 게 만드는 것은 거의 불가능합니다.

  2. 정규식이 정확하지 않은 경우 (0.00001 %의 입력에 대해조차도) 누군가가 애플리케이션을 중단시키는 하나의 입력을 발견 할 수 있기 때문에 보안 문제가 있습니다.

  3. 정규식이 99.99 %의 사례를 포괄 할 수있을만큼 정확하다면이를 완전히 읽을 수없고 유지 보수 할 수 없을 것입니다.

  4. 보통 크기의 입력 파일에서 정규 표현식이 매우 제대로 수행되지 않을 가능성이 큽니다. XML을 처음 접한 것은 들어오는 XML 문서를 올바른 XML 파서로 잘못 분석 한 Perl 스크립트를 대체하는 것이 었으며, 읽을 수없는 코드 300 줄을 누구나 이해할 수있는 100 줄로 바꾸었을뿐만 아니라 사용자 응답 시간을 개선했습니다. 10 초에서 약 0.1 초


1

일반적으로 XML 문법은 결코 정규적이지 않기 때문에 정규식을 사용하여 XML을 구문 분석 할 수 없습니다. 간단히 말해서, 정규 표현식은 셀 수 없습니다 (물론, Perl 정규 표현식은 실제로 계산할 수 있습니다).

동의하지 않습니다. 정규식에서 재귀를 사용하면 열기 및 닫기 태그를 쉽게 찾을 수 있습니다.

여기에 내가 먼저 메시지에서 예 분석 오류를 방지하기 위해 정규 표현식의 예를 보여 주었다.


첫째, 재귀 정규 표현식은 정규 표현식이 아닙니다 (괄호를 보면 재귀 적 인 Perl의 정규 표현식이 HTML을 처리하는 데 필요한 것을 계산할 수 있음을 알 수 있습니다). 둘째, 귀하의 예는 XHTML 또는 XML 형식입니다. HTML이 제대로 구성되지 않았습니다. 셋째, 재귀 정규 표현식 언어 또는 범용 프로그래밍 언어로 작성된 파서를 확장하고 유지 관리하는 것이 더 쉬운 지 스스로에게 묻어 야합니다.
— Chas. Owens

넷째, 귀하의 예제조차도 여전히 유효한 XML 인 동안 사소하게 손상되었습니다. content_block과 id 사이에 하나의 공백을 추가하면 실패합니다. 몇 분 더 보냈다면 코드에서 다른 구조적 오류를 발견 할 것입니다. 좋은 생각이 아닙니다.
— Chas. Owens

1

나는 여기서이 문제에 대한 간단한 대답을 했다 . 100 %를 차지하지는 않지만, 전처리 작업을 기꺼이 수행 할 수있는 방법에 대해 설명합니다.

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