HTML को पार्स करने के लिए नियमित अभिव्यक्तियों का उपयोग करना: क्यों नहीं?


207

यह स्टैकओवरफ्लो पर हर सवाल की तरह लगता है, जहां पूछने वाला HTML से कुछ जानकारी हड़पने के लिए regex का उपयोग कर रहा है, अनिवार्य रूप से एक "उत्तर" होगा जो HTML को पार्स करने के लिए regex का उपयोग नहीं करने के लिए कहता है।

क्यों नहीं? मुझे पता है कि सुंदर सूप की तरह वहाँ बोली "वास्तविक" HTML पार्सर हैं , और मुझे यकीन है कि वे शक्तिशाली और उपयोगी हैं, लेकिन अगर आप कुछ सरल, त्वरित, या गंदा कर रहे हैं, तो क्यों जब कुछ regex बयान सिर्फ ठीक काम करेगा जटिल कुछ का उपयोग कर परेशान?

इसके अलावा, वहाँ कुछ मौलिक है कि मैं regex के बारे में समझ में नहीं आता है जो उन्हें सामान्य रूप से पार्स करने के लिए एक बुरा विकल्प बनाता है?


3
मुझे लगता है कि यह stackoverflow.com/questions/133601
ठग है

23
क्योंकि केवल चक नॉरिस HTML को regex के साथ पार्स कर सकता है (जैसा कि इस प्रसिद्ध ज़ाल्गो चीज़ में समझाया गया है: stackoverflow.com/questions/1732348/… )।
ताकेशिन

1
इस सवाल ने मुझे एक और पूछने के लिए प्रेरित किया जो किसी भी तरह से संबंधित है। मामले में आप रुचि रखते हैं: HTML / XML को पार्स करने के लिए रेगेक्स का उपयोग करना क्यों संभव नहीं है: आम आदमी की शर्तों में एक औपचारिक स्पष्टीकरण
मैक


यह प्रश्न "कॉमन वैलिडेशन टास्क" के तहत स्टैक ओवरफ्लो रेगुलर एक्सप्रेशन एफएक्यू में जोड़ा गया है ।
aliteralmind

जवाबों:


212

नियमित रूप से अभिव्यक्तियों के साथ संपूर्ण HTML पार्सिंग संभव नहीं है, क्योंकि यह उद्घाटन और समापन टैग पर निर्भर करता है जो कि रिफ़ैक्स के साथ संभव नहीं है।

नियमित अभिव्यक्ति केवल नियमित भाषाओं से मेल खा सकती है, लेकिन HTML एक संदर्भ-मुक्त भाषा है और नियमित भाषा नहीं है (जैसा कि @StefanPochmann ने कहा है, नियमित भाषाएं भी संदर्भ-मुक्त हैं, इसलिए संदर्भ-मुक्त का अर्थ नियमित रूप से नहीं है)। HTML पर केवल आप regexps के साथ कर सकते हैं वह आंकड़े हैं लेकिन यह हर शर्त पर काम नहीं करेगा। एक HTML फ़ाइल पेश करना संभव होना चाहिए जो किसी भी नियमित अभिव्यक्ति द्वारा गलत तरीके से मिलान किया जाएगा।


26
अब तक का सबसे अच्छा जवाब। यदि यह केवल नियमित व्याकरण से मेल खा सकता है, तो हमें HTML जैसे संदर्भ-मुक्त व्याकरण को पार्स करने के लिए असीम रूप से बड़े regexp की आवश्यकता होगी। मुझे अच्छा लगता है जब इन बातों के स्पष्ट सैद्धांतिक उत्तर होते हैं।
ntownsend

2
मैंने मान लिया कि हम पर्ल-टाइप रेगेक्स पर चर्चा कर रहे हैं जहां वे वास्तव में नियमित अभिव्यक्ति नहीं हैं।
हांक गे

5
दरअसल,। नेट रेगुलर एक्सप्रेशंस क्लोजिंग टैग्स के साथ कुछ हद तक बैलेंसिंग ग्रुप्स और सावधानी से तैयार किए गए एक्सप्रेशन का इस्तेमाल करके मैचिंग को मैच कर सकते हैं। युक्त सभी एक regexp में इस बात का अभी भी निश्चित रूप से पागल है, यह महान कोड Chtulhu कैसा लगेगा और शायद अच्छी तरह से असली बुलाने होगा। और अंत में यह अभी भी सभी मामलों के लिए काम नहीं करेगा। वे कहते हैं कि यदि आप एक नियमित अभिव्यक्ति लिखते हैं जो किसी भी HTML को सही ढंग से पार्स कर सकती है तो ब्रह्मांड अपने आप गिर जाएगा।
एलेक्स पावेन

5
कुछ रेगेक्स
परिवाद

43
-1 यह उत्तर गलत तर्क से "(क्योंकि HTML एक नियमित भाषा नहीं है") सही निष्कर्ष ("Regex के साथ HTML को पार्स करना बुरा विचार है)"। बात यह है कि ज्यादातर लोगों को आजकल मतलब है जब वे कहते हैं कि "रेगुलर एक्सप्रेशन" (PCRE) अच्छी तरह से सक्षम न केवल विषय से मुक्त व्याकरण (है कि वास्तव में तुच्छ है) को पार्स करने की है, लेकिन यह भी संदर्भ के प्रति संवेदनशील व्याकरण की (देखें stackoverflow.com/questions/7434272/ … )।
निकी सीप

35

Quick Forn finedirty regexp के लिए ठीक होगा। लेकिन जानने के लिए मूल बात यह है कि regexp का निर्माण असंभव है जो HTML को सही ढंग से पार्स करेगा ।

कारण यह है कि regexps मनमाने ढंग से नेस्टेड अभिव्यक्तियों को संभाल नहीं सकता है। देखें नेस्टेड पैटर्न से मेल खाने के लिए क्या रेग्युलर एक्सप्रेशन का इस्तेमाल किया जा सकता है?


1
कुछ रेगेक्स
लिबास

23

( Http://htmlparsing.com/regexes से )

मान लें कि आपको HTML की एक फ़ाइल मिली है, जहाँ आप <img> टैग से URL निकालने की कोशिश कर रहे हैं।

<img src="http://example.com/whatever.jpg">

तो आप पर्ल में इस तरह एक रेगेक्स लिखते हैं:

if ( $html =~ /<img src="(.+)"/ ) {
    $url = $1;
}

इस मामले में, $urlवास्तव में शामिल होंगे http://example.com/whatever.jpg। लेकिन जब आप इस तरह से HTML प्राप्त करना शुरू करते हैं तो क्या होता है:

<img src='http://example.com/whatever.jpg'>

या

<img src=http://example.com/whatever.jpg>

या

<img border=0 src="http://example.com/whatever.jpg">

या

<img
    src="http://example.com/whatever.jpg">

या आपको झूठी सकारात्मकताएं मिलनी शुरू हो जाती हैं

<!-- // commented out
<img src="http://example.com/outdated.png">
-->

यह इतना सरल दिखता है, और यह एक एकल, अपरिवर्तनीय फ़ाइल के लिए सरल हो सकता है, लेकिन कुछ भी जो आप मनमाने ढंग से HTML डेटा पर करने जा रहे हैं, regexes भविष्य के दिल के दर्द के लिए सिर्फ एक नुस्खा है।


4
यह वास्तविक उत्तर प्रतीत होता है - जबकि शायद रेगेक्स के साथ मनमाने ढंग से एचटीएमएल को पार्स करना संभव है क्योंकि आज के रेगेक्स केवल एक परिमित ऑटोमेटा से अधिक हैं, ताकि मनमाने ढंग से HTML पार्स किया जा सके और न ही केवल एक ठोस पृष्ठ जो आपको regexp में HTML पार्सर को फिर से लागू करना है और regexes निश्चित रूप से 1000 गुना अपठनीय हो जाते हैं।
स्मित Johnth

1
अरे एंडी, मैंने एक अभिव्यक्ति के साथ आने का समय लिया जो आपके उल्लिखित मामलों का समर्थन करता है। stackoverflow.com/a/40095824/1204332 मुझे बताएं कि आप क्या सोचते हैं! :)
इवान चेर

2
इस जवाब में तर्क है जिस तरह से पुराना है, और भी कम आज की तुलना में यह मूल रूप से किया था (जो मुझे लगता है कि ऐसा नहीं है) लागू होता है। (ओपी को उद्धृत करते हुए: "यदि आप कुछ सरल, त्वरित, या गंदा कर रहे हैं ...")
एसजेड।

16

दो त्वरित कारण:

  • दुर्भावनापूर्ण इनपुट के लिए खड़े होने वाले एक रेक्स को लिखना कठिन है; एक prebuilt उपकरण का उपयोग करने की तुलना में कठिन है
  • एक regex लिखना जो हास्यास्पद मार्कअप के साथ काम कर सकता है जिसे आप अनिवार्य रूप से अटकाएंगे, कठिन है; एक prebuilt उपकरण का उपयोग करने से कठिन है

सामान्य रूप से पार्स करने के लिए रेगेक्स की उपयुक्तता के बारे में: वे उपयुक्त नहीं हैं। क्या आपने कभी देखा है कि अधिकांश भाषाओं को पार्स करने के लिए आपको किस प्रकार के रीगेक्स की आवश्यकता होती है?


2
वाह? 2 साल के बाद एक गिरावट? यदि कोई सोच रहा था, तो मैंने "क्योंकि यह सैद्धांतिक रूप से असंभव है" नहीं कहा, क्योंकि प्रश्न "त्वरित-और-गंदे" के बारे में स्पष्ट रूप से पूछा गया था, "सही" नहीं। ओपी ने स्पष्ट रूप से पहले से ही उत्तर पढ़े जो सैद्धांतिक रूप से असंभव क्षेत्र को कवर करते थे और अभी भी संतुष्ट नहीं थे।
हैंक गे

1
5+ वर्षों के बाद उत्थान करें। :) के रूप में आप नीचे क्यों प्राप्त हो सकता है के लिए, मैं कहने के लिए योग्य नहीं हूँ, लेकिन व्यक्तिगत रूप से, मैं कुछ उदाहरणों को देखना पसंद करूंगा, या बयानबाजी के प्रश्न के बजाय स्पष्टीकरण।
एडम जेन्सेन

3
अनिवार्य रूप से सभी त्वरित और गंदे HTML पार्सिंग जो शिपिंग उत्पादों या आंतरिक उपकरणों में किए जाते हैं, एक अंतराल सुरक्षा छेद, या एक बग होने की प्रतीक्षा करता है। इसे उत्साह के साथ हतोत्साहित करना होगा। यदि कोई एक रेगेक्स का उपयोग कर सकता है, तो एक उचित HTML पार्सर का उपयोग कर सकता है।
मोनिका

16

जहां तक ​​पार्सिंग जाता है, नियमित अभिव्यक्ति "लेक्सिकल विश्लेषण" (लेक्सर) चरण में उपयोगी हो सकती है, जहां इनपुट टोकन में टूट जाता है। यह वास्तविक "पार्स ट्री का निर्माण" चरण में कम उपयोगी है।

एक HTML पार्सर के लिए, मैं अपेक्षा करता हूं कि यह केवल अच्छी तरह से बनाए गए HTML को स्वीकार करे और इसके लिए क्षमताओं की आवश्यकता होती है जो एक नियमित अभिव्यक्ति कर सकते हैं (वे "गिनती" नहीं कर सकते हैं और यह सुनिश्चित कर सकते हैं कि दिए गए प्रारंभिक तत्व उसी संख्या द्वारा संतुलित हैं। तत्वों का समापन)।


8

क्योंकि HTML को "स्क्रू अप" करने के कई तरीके हैं जो ब्राउज़र एक उदार तरीके से व्यवहार करेंगे, लेकिन सभी मामलों को नियमित अभिव्यक्तियों के साथ कवर करने के लिए ब्राउज़र के उदार व्यवहार को पुन: पेश करने के लिए काफी प्रयास करना होगा, इसलिए आपका रेगेक्स अनिवार्य रूप से कुछ विशेष रूप से विफल हो जाएगा मामले, और वह संभवतः आपके सिस्टम में गंभीर सुरक्षा अंतराल का परिचय देंगे।


1
बहुत सच है, HTML का अधिकांश हिस्सा भयानक लगता है। मुझे समझ में नहीं आता है कि एक असफल नियमित अभिव्यक्ति गंभीर सुरक्षा अंतराल कैसे पेश कर सकती है। क्या आप एक उदाहरण दे सकते हैं?
ntownsend

4
ntownsend: उदाहरण के लिए, आपको लगता है कि आपने HTML से सभी स्क्रिप्ट टैग छीन लिए हैं, लेकिन आपका regex एक विशेष मामले को कवर करने में विफल रहता है (जो मान लें, केवल IE6 पर काम करता है): बूम, आपके पास एक XSS अशिष्टता है!
तमसा Czinege

1
यह एक कड़ाई से काल्पनिक उदाहरण था क्योंकि अधिकांश वास्तविक दुनिया उदाहरण इन टिप्पणियों में फिट होने के लिए बहुत जटिल हैं, लेकिन आप इस विषय पर त्वरित googling द्वारा कुछ पा सकते हैं।
तमसा सीज़ेगें

3
सुरक्षा कोण का उल्लेख करने के लिए +1। जब आप पूरे इंटरनेट के साथ हस्तक्षेप कर रहे हैं तो आप हैकी "ज्यादातर समय काम करता है" कोड लिखने का जोखिम नहीं उठा सकते हैं।
15:15 बजे j_random_hacker

7

समस्या यह है कि ज्यादातर उपयोगकर्ता जो एक प्रश्न पूछते हैं जो HTML और regex के साथ करना है, क्योंकि वे स्वयं regex नहीं ढूँढ सकते हैं - यह काम करता है। फिर किसी को यह सोचना होगा कि क्या डोम या एसएएक्स पार्सर या कुछ समान का उपयोग करते समय सब कुछ आसान होगा। XML- जैसी दस्तावेज़ संरचनाओं के साथ काम करने के उद्देश्य से इन्हें अनुकूलित और निर्मित किया गया है।

निश्चित रूप से, ऐसी समस्याएं हैं जिन्हें नियमित अभिव्यक्तियों के साथ आसानी से हल किया जा सकता है। लेकिन जोर आसानी से है

यदि आप बस सभी URL ढूंढना चाहते हैं, जो इस तरह दिखते हैं जैसे http://.../आप regexps के साथ ठीक हैं। लेकिन अगर आप उन सभी URL को ढूंढना चाहते हैं जो एक इन-एलिमेंट में हैं, जिसमें 'mylink' क्लास है, तो आप शायद एक उपयुक्त पार्सर का उपयोग कर सकते हैं।


6

नियमित अभिव्यक्तियाँ एक नेस्टेड टैग संरचना को संभालने के लिए डिज़ाइन नहीं की गई थीं, और यह वास्तविक HTML के साथ मिलने वाले सभी संभावित किनारे के मामलों को संभालने के लिए सबसे जटिल (सबसे खराब, असंभव) है।


6

मेरा मानना ​​है कि उत्तर गणना सिद्धांत में निहित है। रेगेक्स का उपयोग करते हुए एक भाषा के लिए इसे "नियमित" ( लिंक ) परिभाषा के अनुसार होना चाहिए । HTML एक नियमित भाषा नहीं है क्योंकि यह एक नियमित भाषा के लिए कई मानदंडों को पूरा नहीं करता है (html कोड में निहित घोंसले के शिकार के कई स्तरों के साथ बहुत कुछ करना है)। यदि आप गणना के सिद्धांत में रुचि रखते हैं तो मैं इस पुस्तक की सिफारिश करूंगा ।


1
मैंने वास्तव में उस पुस्तक को पढ़ा है। यह सिर्फ मेरे लिए नहीं था कि HTML एक संदर्भ-मुक्त भाषा है।
ntownsend

4

यह अभिव्यक्ति HTML तत्वों से विशेषताएँ प्राप्त करती है। यह समर्थन करता है:

  • अयोग्य / उद्धृत विशेषताएँ,
  • सिंगल / डबल कोट्स,
  • विशेषताओं के अंदर बच गए उद्धरण,
  • सिग्नल के बराबर स्थान,
  • किसी भी संख्या के गुण,
  • केवल टैग के अंदर विशेषताओं के लिए जाँच करें,
  • टिप्पणियों से बच, और
  • एक विशेषता मान के भीतर विभिन्न उद्धरणों का प्रबंधन करें।

(?:\<\!\-\-(?:(?!\-\-\>)\r\n?|\n|.)*?-\-\>)|(?:<(\S+)\s+(?=.*>)|(?<=[=\s])\G)(?:((?:(?!\s|=).)*)\s*?=\s*?[\"']?((?:(?<=\")(?:(?<=\\)\"|[^\"])*|(?<=')(?:(?<=\\)'|[^'])*)|(?:(?!\"|')(?:(?!\/>|>|\s).)+))[\"']?\s*)

इसे देखें । यह "गिसक्स" झंडे के साथ बेहतर काम करता है, जैसा कि डेमो में है।


1
यह तो बहुत ही मज़ेदार है। पठनीय नहीं, शायद डिबग करना कठिन है लेकिन फिर भी: प्रभावशाली काम!
एरिक डुमिनील

यह अभी भी अस्पष्ट रूप से मानता है कि HTML अच्छी तरह से गठित है,। संदर्भ मिलान के बिना, यह उन संदर्भों में स्पष्ट URL से मेल खाएगा जहां आप आम तौर पर उनका मिलान नहीं करना चाहते हैं, जैसे किसी <script>टैग के अंदर जावास्क्रिप्ट कोड का एक टुकड़ा ।
ट्रिपलए

4

HTML / XML को मार्कअप और सामग्री में विभाजित किया गया है। रेगेक्स केवल एक शाब्दिक टैग पार्स करने के लिए उपयोगी है। मुझे लगता है कि आप सामग्री घटा सकते हैं। यह SAX पार्सर के लिए एक अच्छा विकल्प होगा। टैग और सामग्री को एक उपयोगकर्ता परिभाषित फ़ंक्शन तक पहुंचाया जा सकता है, जहां तत्वों के घोंसले बनाने / बंद करने पर नज़र रखी जा सकती है।

जहाँ तक सिर्फ टैग्स को पार्स करने का है, इसे रेगेक्स के साथ किया जा सकता है और इसका इस्तेमाल डॉक्यूमेंट्स से टैग्स को हटाने के लिए किया जाता है।

परीक्षण के वर्षों में, मैंने उस तरह से ब्राउज़रों को गुप्त पाया है जो टैग को अच्छी तरह से और बीमार दोनों तरह से बनाते हैं।

सामान्य तत्व इस फॉर्म के साथ पार्स किए जाते हैं:

इन टैग्स के मूल में इस regex का उपयोग किया गया है

 (?:
      " [\S\s]*? " 
   |  ' [\S\s]*? ' 
   |  [^>]? 
 )+

आप इसे [^>]?एक विकल्प के रूप में देखेंगे । यह बीमार-निर्मित टैग से असंतुलित उद्धरणों से मेल खाएगा।

यह भी है, नियमित अभिव्यक्ति के लिए सभी बुराई का सबसे मूल जड़ है । जिस तरह से इसका उपयोग किया जाता है वह एक लालसा को ट्रिगर करेगा, यह संतुष्ट करने के लिए लालची होगा, कि मात्रा निर्धारित कंटेनर से मेल खाना चाहिए।

यदि निष्क्रिय रूप से उपयोग किया जाता है, तो कभी कोई समस्या नहीं होती है लेकिन, यदि आप किसी चीज़ को एक वांछित विशेषता / मूल्य जोड़ी के साथ जोड़कर मिलान करने के लिए मजबूर करते हैं, और बैकट्रैकिंग से पर्याप्त सुरक्षा प्रदान नहीं करते हैं, तो यह नियंत्रण से बाहर है।

यह केवल सादे पुराने टैग के लिए सामान्य रूप है। [\w:]टैग नाम का प्रतिनिधित्व करते हुए नोटिस करें? वास्तव में, टैग नाम का प्रतिनिधित्व करने वाले कानूनी चरित्र यूनिकोड वर्णों की एक अविश्वसनीय सूची है।

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

आगे बढ़ते हुए, हम यह भी देखते हैं कि आप सभी टैग्स को पार्स किए बिना किसी विशिष्ट टैग की खोज नहीं कर सकते । मेरा मतलब है कि आप कर सकते हैं, लेकिन इसमें क्रियाओं के संयोजन का उपयोग करना होगा जैसे (* SKIP) (* FAIL) लेकिन फिर भी सभी टैग को पार्स करना होगा।

कारण यह है कि टैग सिंटैक्स को अन्य टैग्स आदि के अंदर छिपाया जा सकता है।

इसलिए, सभी टैग्स को निष्क्रिय करने के लिए, नीचे दिए गए एक regex की आवश्यकता होती है। यह विशेष रूप से अदृश्य सामग्री से भी मेल खाता है ।

नए HTML या xml या किसी अन्य नए निर्माण को विकसित करने के लिए, बस इसे एक विकल्प के रूप में जोड़ें।


वेब पेज नोट - मैंने कभी ऐसा वेब पेज (या एक्सएचटीएमएल / एक्सएमएल) नहीं देखा है
जिसके साथ यह परेशानी थी। अगर आपको एक मिल जाए, तो मुझे बताएं।

प्रदर्शन नोट - यह त्वरित है। यह सबसे तेज टैग पार्सर है जिसे मैंने देखा है
(तेजी से हो सकता है, कौन जानता है)।
मेरे कई विशिष्ट संस्करण हैं। यह स्क्रैपर के रूप में भी उत्कृष्ट है
(यदि आप हाथों पर टाइप कर रहे हैं)।


कच्चे रेगेक्स को पूरा करें

<(?:(?:(?:(script|style|object|embed|applet|noframes|noscript|noembed)(?:\s+(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+)?\s*>)[\S\s]*?</\1\s*(?=>))|(?:/?[\w:]+\s*/?)|(?:[\w:]+\s+(?:"[\S\s]*?"|'[\S\s]*?'|[^>]?)+\s*/?)|\?[\S\s]*?\?|(?:!(?:(?:DOCTYPE[\S\s]*?)|(?:\[CDATA\[[\S\s]*?\]\])|(?:--[\S\s]*?--)|(?:ATTLIST[\S\s]*?)|(?:ENTITY[\S\s]*?)|(?:ELEMENT[\S\s]*?))))>

स्वरूपित रूप

 <
 (?:
      (?:
           (?:
                # Invisible content; end tag req'd
                (                             # (1 start)
                     script
                  |  style
                  |  object
                  |  embed
                  |  applet
                  |  noframes
                  |  noscript
                  |  noembed 
                )                             # (1 end)
                (?:
                     \s+ 
                     (?>
                          " [\S\s]*? "
                       |  ' [\S\s]*? '
                       |  (?:
                               (?! /> )
                               [^>] 
                          )?
                     )+
                )?
                \s* >
           )

           [\S\s]*? </ \1 \s* 
           (?= > )
      )

   |  (?: /? [\w:]+ \s* /? )
   |  (?:
           [\w:]+ 
           \s+ 
           (?:
                " [\S\s]*? " 
             |  ' [\S\s]*? ' 
             |  [^>]? 
           )+
           \s* /?
      )
   |  \? [\S\s]*? \?
   |  (?:
           !
           (?:
                (?: DOCTYPE [\S\s]*? )
             |  (?: \[CDATA\[ [\S\s]*? \]\] )
             |  (?: -- [\S\s]*? -- )
             |  (?: ATTLIST [\S\s]*? )
             |  (?: ENTITY [\S\s]*? )
             |  (?: ELEMENT [\S\s]*? )
           )
      )
 )
 >

3

"हालांकि यह निर्भर करता है"। यह सच है कि regexes HTML को सही सटीकता के साथ पार्स नहीं कर सकता और न ही यहां दिए गए सभी कारणों से। यदि, हालांकि, यह गलत होने (जैसे नेस्टेड टैग्स को हैंडल नहीं करना) के परिणाम मामूली हैं, और यदि आपके वातावरण में regexes सुपर-सुविधाजनक हैं (जैसे कि जब आप पर्ल को हैक कर रहे हों), तो आगे बढ़ें।

मान लें कि आप ओह, शायद आपकी साइट से लिंक करने वाले वेब पेजों को पार्स कर रहे हैं - शायद आपने उन्हें Google लिंक खोज के साथ पाया है - और आप चाहते हैं कि संदर्भ का एक सामान्य विचार आपके लिंक को घेरे रहे। आप एक छोटी सी रिपोर्ट चलाने की कोशिश कर रहे हैं जो आपको स्पैम, कुछ इस तरह से लिंक करने के लिए सचेत कर सकती है।

उस मामले में, कुछ दस्तावेजों की गलत व्याख्या करना बहुत बड़ी बात नहीं है। कोई भी नहीं है लेकिन आप गलतियों को देखेंगे, और यदि आप बहुत भाग्यशाली हैं तो कुछ पर्याप्त होंगे जो आप व्यक्तिगत रूप से अनुसरण कर सकते हैं।

मुझे लगता है मैं कह रहा हूं कि यह एक व्यापार है। कभी-कभी सही पार्सर को लागू करना या उसका उपयोग करना - जितना आसान हो सकता है - उतनी परेशानी नहीं हो सकती है यदि सटीकता महत्वपूर्ण नहीं है।

बस अपनी धारणाओं से सावधान रहें। मैं कुछ तरीकों के बारे में सोच सकता हूं कि यदि आप किसी चीज़ को पार्स करने की कोशिश कर रहे हैं तो उदाहरण के लिए regexp शॉर्टकट बैकफ़ायर कर सकता है।


3

निश्चित रूप से ऐसे मामले हैं जहां HTML से कुछ जानकारी को पार्स करने के लिए एक नियमित अभिव्यक्ति का उपयोग करना सही तरीका है - यह विशिष्ट स्थिति पर बहुत कुछ निर्भर करता है।

ऊपर आम सहमति यह है कि सामान्य तौर पर यह एक बुरा विचार है। हालाँकि अगर HTML संरचना ज्ञात है (और बदलने की संभावना नहीं है) तो यह अभी भी एक मान्य दृष्टिकोण है।


3

ध्यान रखें कि जब HTML स्वयं नियमित नहीं होता है, तो आपके द्वारा देखे जा रहे पृष्ठ के भाग नियमित हो सकते हैं।

उदाहरण के लिए, <form>टैग के लिए नेस्टेड होना एक त्रुटि है ; यदि वेब पेज सही तरीके से काम कर रहा है, तो हड़पने के लिए एक नियमित अभिव्यक्ति का उपयोग <form>करना पूरी तरह से उचित होगा।

मैंने हाल ही में केवल सेलेनियम और नियमित अभिव्यक्ति का उपयोग करते हुए कुछ वेब स्क्रैपिंग किया था। मैं इसके साथ दूर हो गया क्योंकि मैं जो डेटा चाहता था उसे <form>एक सरल तालिका प्रारूप में डाल दिया गया था (इसलिए मैं भी गिन सकता था <table>, <tr>और <td>गैर-नेस्टेड होने के लिए - जो वास्तव में अत्यधिक असामान्य है)। कुछ अंशों में, नियमित रूप से अभिव्यक्तियाँ भी लगभग आवश्यक थीं, क्योंकि मुझे जिस संरचना तक पहुंचने की आवश्यकता थी, उनमें से कुछ को टिप्पणियों द्वारा सीमांकित किया गया था। (सुंदर सूप आपको टिप्पणी दे सकता है, लेकिन सुंदर सूप का उपयोग करके हड़पना <!-- BEGIN -->और <!-- END -->ब्लॉक करना मुश्किल होगा ।)

अगर मुझे नेस्टेड टेबल्स के बारे में चिंता करना था, हालांकि, मेरा दृष्टिकोण बस काम नहीं करेगा! मुझे सुंदर सूप पर वापस गिरना होगा। फिर भी, हालांकि, कभी-कभी आप अपनी ज़रूरत के अनुसार चंक को हथियाने के लिए एक नियमित अभिव्यक्ति का उपयोग कर सकते हैं, और फिर वहां से नीचे ड्रिल कर सकते हैं।


2

दरअसल, PHP में regex के साथ HTML पार्स करना पूरी तरह से संभव है। आपको केवल नेस्टेड टैग्स को प्राप्त करने के लिए प्रत्येक बार ungreedy Speciers का उपयोग करते हुए वहाँ से regex strrposको खोजने <और दोहराने के लिए पूरे स्ट्रिंग को पीछे की तरफ पार्स करना होगा। बड़ी चीजों पर फैंसी और बहुत धीमी गति से नहीं, लेकिन मैंने इसे अपनी वेबसाइट के लिए अपने व्यक्तिगत टेम्पलेट संपादक के लिए उपयोग किया। मैं वास्तव में HTML पार्स नहीं कर रहा था, लेकिन कुछ टेबल्स टैग जो मैंने डेटाबेस प्रविष्टियों को क्वेरी करने के लिए डेटा की तालिकाओं को प्रदर्शित करने के लिए किए थे (मेरा <#if()>टैग इस तरह से विशेष प्रविष्टियों को उजागर कर सकता है)। मैं एक स्व-निर्मित टैग (उनके भीतर बहुत गैर-XML डेटा के साथ) पर XML पार्सर के लिए जाने के लिए तैयार नहीं था।

इसलिए, भले ही यह प्रश्न काफी हद तक मृत है, फिर भी यह Google खोज में दिखाई देता है। मैंने इसे पढ़ा और सोचा "चुनौती स्वीकार की" और सब कुछ बदलने के बिना अपना सरल कोड फिक्स करना समाप्त कर दिया। किसी समान कारण की खोज करने वाले को अलग राय देने का निर्णय लिया गया। इसके अलावा अंतिम उत्तर 4 घंटे पहले पोस्ट किया गया था इसलिए यह अभी भी एक गर्म विषय है।


2
-1 एक सुझाव के सुझाव के लिए। क्या आपने टैग और समापन कोण ब्रैकेट के बीच व्हाट्सएप पर विचार किया था? (जैसे, <tag >) क्या आपने टिप्पणी-बंद समापन टैग पर विचार किया है? (जैसे, <tag> <!-- </tag> -->) क्या आपने सीडीएटीए पर विचार किया? क्या आपने असंगत-केस टैग पर विचार किया? (जैसे, <Tag> </tAG>) क्या आपने इस पर भी विचार किया?

1
आपके कुछ कस्टम टैग के विशेष मामले में, हाँ, नियमित अभिव्यक्ति अच्छी तरह से काम करती हैं। तो ऐसा नहीं है कि उनमें से आपका उपयोग आपके विशेष मामले में एक गलती थी । हालांकि, यह HTML नहीं है, और कह रहा है कि "PHP में regex के साथ HTML पार्सिंग पूरी तरह से संभव है" केवल फ्लैट-आउट झूठी है, और एक TERRIBLE विचार है। वास्तविक एचटीएमएल की विसंगतियां (और मेरे द्वारा सूचीबद्ध कुछ से अधिक तरीके हैं) यही कारण है कि आपको नियमित रूप से अभिव्यक्ति के साथ वास्तविक HTML को कभी भी पार्स नहीं करना चाहिए। देखें, ठीक है, इस प्रश्न के अन्य सभी उत्तर, साथ ही साथ जो मैंने ऊपर मेरी अन्य टिप्पणी में जोड़ा है।
rmunn

2
PHP एक ट्यूरिंग-पूर्ण भाषा है, इसलिए यह बिल्कुल भी सपाट नहीं है। HTML को पार्स करने सहित सब कुछ संभव है। टैग में रिक्तियाँ कभी भी एक समस्या नहीं थीं और मैंने इसे टैग तत्वों को क्रम में सूचीबद्ध करने के लिए अनुकूलित किया है। असंगत आवरण के साथ मेरे उपयोग ने स्वचालित रूप से सही किए गए टैग, बहुत पहले चरण में टिप्पणी की गई सामग्री को छीन लिया और कुछ बाद के परिवर्धन के बाद सभी प्रकार के टैग आसानी से जोड़े जा सकते हैं (हालांकि यह मामला-संवेदनशील है, मेरी अपनी पसंद से)। और मुझे पूरा यकीन है कि सीडीएटीए वास्तव में एक्सएमएल तत्व है, एचटीएमएल नहीं।
डेजी

2
मेरी पुरानी विधि (जो मैंने यहाँ वर्णित की है) बहुत अक्षम थी और मैंने हाल ही में बहुत सारे सामग्री संपादकों का फिर से लिखना शुरू किया है। जब इन चीजों को करने की बात आती है, तो संभावना मुद्दा नहीं है; सबसे अच्छा तरीका हमेशा मुख्य चिंता का विषय है। असली जवाब "PHP में ऐसा करने का कोई आसान तरीका नहीं है"। NO ONE का कहना है कि PHP में ऐसा करने का कोई तरीका नहीं है या यह एक भयानक विचार है, लेकिन यह regex के साथ असंभव है, जिसे मैंने ईमानदारी से कभी नहीं आजमाया है, लेकिन मेरे जवाब में एक बड़ी खामी यह है कि मुझे लगा कि सवाल regex का जिक्र था PHP के संदर्भ में, जो कि जरूरी नहीं है।
डेजी

2

मैंने इसके लिए एक रेक्सक्स पर भी हाथ आजमाया। यह अगले HTML टैग के साथ जोड़े गए सामग्री के विखंडन को खोजने के लिए ज्यादातर उपयोगी है, और यह करीब टैग मिलान के लिए नहीं दिखता है , लेकिन यह करीब टैग चुन लेगा। अपनी खुद की भाषा में एक स्टैक रोल करें ताकि वे जांच सकें।

'Sx' विकल्पों के साथ प्रयोग करें। 'जी' भी अगर आप भाग्यशाली महसूस कर रहे हैं:

(?P<content>.*?)                # Content up to next tag
(?P<markup>                     # Entire tag
  <!\[CDATA\[(?P<cdata>.+?)]]>| # <![CDATA[ ... ]]>
  <!--(?P<comment>.+?)-->|      # <!-- Comment -->
  </\s*(?P<close_tag>\w+)\s*>|  # </tag>
  <(?P<tag>\w+)                 # <tag ...
    (?P<attributes>
      (?P<attribute>\s+
# <snip>: Use this part to get the attributes out of 'attributes' group.
        (?P<attribute_name>\w+)
        (?:\s*=\s*
          (?P<attribute_value>
            [\w:/.\-]+|         # Unquoted
            (?=(?P<_v>          # Quoted
              (?P<_q>['\"]).*?(?<!\\)(?P=_q)))
            (?P=_v)
          ))?
# </snip>
      )*
    )\s*
  (?P<is_self_closing>/?)   # Self-closing indicator
  >)                        # End of tag

यह एक पायथन के लिए डिज़ाइन किया गया है (यह अन्य भाषाओं के लिए काम कर सकता है, इसे आज़माया नहीं गया है, यह सकारात्मक लुकहैड्स, नकारात्मक लुकबाइंड्स, और बैकरेफेरेंस नाम का उपयोग करता है)। समर्थन:

  • खुला टैग - <div ...>
  • बंद टैग - </div>
  • टिप्पणी - <!-- ... -->
  • CDATA - <![CDATA[ ... ]]>
  • स्व-समापन टैग - <div .../>
  • वैकल्पिक विशेषता मान - <input checked>
  • अयोग्य / उद्धृत विशेषता मान - <div style='...'>
  • सिंगल / डबल कोट्स - <div style="...">
  • बच गए उद्धरण - <a title='John\'s Story'>
    (यह वास्तव में मान्य HTML नहीं है, लेकिन मैं एक अच्छा लड़का हूं)
  • लगभग बराबर चिन्ह वाले स्थान - <a href = '...'>
  • दिलचस्प बिट्स के लिए नामित नाम

यह भी विकृत टैग पर नहीं ट्रिगर, जैसे जब आप किसी भूल के बारे में बहुत अच्छा है <या >

यदि आपका रेगेक्स फ्लेवर बार-बार नामित कैप्चर का समर्थन करता है तो आप सुनहरे हैं, लेकिन पायथन reनहीं करता है (मुझे पता है कि रेगेक्स करता है, लेकिन मुझे वेनिला पायथन का उपयोग करने की आवश्यकता है)। यहाँ आपको क्या मिलेगा:

  • content- अगले टैग तक सभी सामग्री। आप इसे छोड़ सकते हैं।
  • markup - इसमें सब कुछ के साथ पूरा टैग।
  • comment - यदि यह एक टिप्पणी है, तो टिप्पणी सामग्री।
  • cdata- यदि यह एक है <![CDATA[...]]>, तो सीडीएटीए सामग्री।
  • close_tag- यदि यह एक करीबी टैग ( </div>), टैग नाम है।
  • tag- यदि यह एक खुला टैग ( <div>), टैग नाम है।
  • attributes- टैग के अंदर सभी विशेषताएँ। यदि आपको बार-बार समूह नहीं मिलते हैं, तो सभी विशेषताओं को प्राप्त करने के लिए इसका उपयोग करें।
  • attribute - दोहराया, प्रत्येक विशेषता।
  • attribute_name - बार-बार, प्रत्येक विशेषता नाम।
  • attribute_value- दोहराया, प्रत्येक विशेषता मूल्य। इसमें उद्धरण शामिल हैं यदि यह उद्धृत किया गया था।
  • is_self_closing- यह है /अगर यह एक स्व-समापन टैग है, अन्यथा कुछ भी नहीं।
  • _qऔर _v- इन पर ध्यान न दें; वे आंतरिक रूप से बैकरेफरेंस के लिए उपयोग किए जाते हैं।

यदि आपका रेगेक्स इंजन बार-बार कैप्चर नाम का समर्थन नहीं करता है, तो एक खंड है जिसे आप प्रत्येक विशेषता प्राप्त करने के लिए उपयोग कर सकते हैं। attributesप्रत्येक को प्राप्त करने के लिए समूह से उस रेगेक्स को चलाएं attribute, attribute_nameऔर attribute_valueउससे बाहर निकलें।

यहाँ डेमो: https://regex101.com/r/mH8jSu/11


1

HTML जैसी भाषा के लिए नियमित अभिव्यक्ति पर्याप्त शक्तिशाली नहीं है। ज़रूर, कुछ उदाहरण हैं जहाँ आप नियमित अभिव्यक्ति का उपयोग कर सकते हैं। लेकिन सामान्य तौर पर यह पार्सिंग के लिए उपयुक्त नहीं है।


0

आप, जानते हैं ... आप की मानसिकता बहुत है और मैं ऐसा नहीं कर सकता, मुझे लगता है कि बाड़ के दोनों तरफ हर कोई सही और गलत है। आप इसे कर सकते हैं, लेकिन इसके खिलाफ केवल एक रेगेक्स चलाने की तुलना में थोड़ा अधिक प्रसंस्करण होता है। ले लो इस एक उदाहरण के रूप (मैं एक घंटे के इस अंदर लिखा था)। यह मानता है कि HTML पूरी तरह से मान्य है, लेकिन आप उपर्युक्त regex को लागू करने के लिए किस भाषा का उपयोग कर रहे हैं, इसके आधार पर, आप यह सुनिश्चित करने के लिए HTML के कुछ फिक्सिंग कर सकते हैं कि यह सफल होगा। उदाहरण के लिए, उन क्लोजिंग टैग्स को हटाना जो वहां होने ही नहीं चाहिए:</img> उदाहरण के लिए। फिर, उन तत्वों को बंद करने वाले एकल HTML फ़ॉरवर्ड स्लैश को जोड़ें जो उन्हें याद कर रहे हैं, आदि।

मैं इसका उपयोग एक पुस्तकालय लिखने के संदर्भ में करूंगा जो मुझे HTML तत्व पुनर्प्राप्ति akin को जावास्क्रिप्ट के प्रदर्शन के लिए अनुमति देगा [x].getElementsByTagName() उदाहरण के लिए । मैं अभी उस कार्यक्षमता को विभाजित करूँगा, जिसे मैंने रेगेक्स के DEFINE अनुभाग में लिखा था और इसका उपयोग तत्वों के एक पेड़ के अंदर कदम रखने के लिए किया था, एक समय में।

तो, क्या यह HTML को मान्य करने के लिए अंतिम 100% उत्तर होगा? नहीं, लेकिन यह एक शुरुआत है और थोड़े अधिक काम के साथ, यह किया जा सकता है। हालांकि, इसे एक रेगेक्स निष्पादन के अंदर करने की कोशिश करना व्यावहारिक नहीं है, न ही कुशल।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.