2010-06-30 16 views
35

तर्क के लिए एक HTML पार्सर मानते हैं।एक पार्सर (उदाहरण के लिए, एचटीएमएल) कैसे काम करता है?

मैंने पढ़ा है कि यह टोकन को पहले सब कुछ टोकन करता है, और फिर इसे पार करता है।

टोकन का मतलब क्या है?

क्या पार्सर प्रत्येक चरित्र को प्रत्येक को पढ़ता है, संरचना को स्टोर करने के लिए एक बहु आयामी सरणी का निर्माण करता है?

उदाहरण के लिए, क्या यह < पढ़ता है और फिर तत्व को कैप्चर करना शुरू करता है, और फिर एक बार यह > (एक विशेषता के बाहर) को पूरा करने के बाद इसे किसी सरणी स्टैक पर धक्का दिया जाता है?

मुझे जानने के लिए दिलचस्पी है (मैं उत्सुक हूं)।

अगर मुझे HTML Purifier जैसे कुछ के स्रोत के माध्यम से पढ़ना था, तो क्या यह मुझे एक अच्छा विचार देगा कि HTML को कैसे पार्स किया गया है?

+0

देखो http://en.wikipedia.org/wiki/Lexical_parser पर एक बहुत ही संक्षिप्त परिचय के लिए; वहां 'पार्सिंग' आलेख भी देखें। और एचटीएमएल शोधक, कुछ बिंदु पर, बिल्कुल यही करता है। – Piskvor

+0

एचटीएमएल एजिलिटी पैक ओपन सोर्स है और यह टोकननाइज़र पर आधारित है। http://htmlagilitypack.codeplex.com/ – Oded

+0

यदि आप सी (ओकंपल, लिस्प) पढ़ सकते हैं, तो yacc/lex (ocamlyacc/ocamllex, cl-yacc/cl-lex ...) पर कुछ ट्यूटोरियल्स को देखने का प्रयास करें। आप कोड से जल्दी मूल बातें समझेंगे। अगर आप कोड पढ़ सकते हैं। – Amadan

उत्तर

29

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

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

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

एक सामान्य तरीके से, आप इस बारे में सही हैं कि एक पार्सर कैसे काम करता है, लेकिन (कम से कम एक सामान्य पार्सर में) यह एक बयान को पार करने के कार्य के दौरान एक ढेर का उपयोग करता है, लेकिन यह एक बयान का प्रतिनिधित्व करने के लिए क्या बनाता है एक पेड़ (और सार सिंटेक्स ट्री, उर्फ ​​एएसटी), एक बहुआयामी सरणी नहीं।

एचटीएमएल पार्सिंग की जटिलता के आधार पर, मैं इसके लिए एक पार्सर को आरक्षित करना चाहता हूं जब तक आप पहले कुछ अन्य लोगों को पढ़ नहीं लेते। यदि आप कुछ को चारों ओर देखते हैं, तो आपको गणितीय अभिव्यक्तियों जैसी चीजों के लिए पार्सर्स/लेक्सर्स की उचित संख्या मिलनी चाहिए जो संभवतः एक परिचय के रूप में अधिक उपयुक्त हैं (छोटे, सरल, समझने में आसान इत्यादि।)

52

Tokenizing, कुछ ही कदम की रचना की जा सकती है, उदाहरण के लिए, आप इस एचटीएमएल कोड है, तो:

<html> 
    <head> 
     <title>My HTML Page</title> 
    </head> 
    <body> 
     <p style="special"> 
      This paragraph has special style 
     </p> 
     <p> 
      This paragraph is not special 
     </p> 
    </body> 
</html> 

tokenizer महत्वपूर्ण टोकन, को त्यागकर व्हाइटस्पेस के एक फ्लैट की सूची पर कि स्ट्रिंग परिवर्तित कर सकते हैं (धन्यवाद, सुधार के लिए) Sasq:

["<", "html", ">", 
    "<", "head", ">", 
     "<", "title", ">", "My HTML Page", "</", "title", ">", 
    "</", "head", ">", 
    "<", "body", ">", 
     "<", "p", "style", "=", "\"", "special", "\"", ">", 
      "This paragraph has special style", 
     "</", "p", ">", 
     "<", "p", ">", 
      "This paragraph is not special", 
     "</", "p", ">", 
    "</", "body", ">", 
"</", "html", ">" 
] 

वहाँ कई tokenizing हो सकता है गुजरता निम्नलिखित काल्पनिक HTML पार्सर कर सकता की तरह भी उच्च स्तर टोकन की एक सूची के लिए टोकन की एक सूची कन्वर्ट करने के लिए (जो अब भी है एक फ्लैट सूची):

("<html>", {}, [ 
    ("<head>", {}, [ 
     ("<title>", {}, ["My HTML Page"]), 
    ]), 
    ("<body>", {}, [ 
     ("<p>", {"style": "special"}, ["This paragraph has special style"]), 
     ("<p>", {}, ["This paragraph is not special"]), 
    ]), 
]) 
:

[("<html>", {}), 
    ("<head>", {}), 
     ("<title>", {}), "My HTML Page", "</title>", 
    "</head>", 
    ("<body>", {}), 
     ("<p>", {"style": "special"}), 
      "This paragraph has special style", 
     "</p>", 
     ("<p>", {}), 
      "This paragraph is not special", 
     "</p>", 
    "</body>", 
"</html>" 
] 

तो पार्सर एक पेड़ या ग्राफ जो ऐसे तरीके से उपयोग करने के लिए और अधिक सुविधाजनक है में स्रोत पाठ का प्रतिनिधित्व करता है के रूप में टोकन की उस सूची में कनवर्ट करता है/इस कार्यक्रम के द्वारा हेरफेर इस बिंदु पर

, पार्सिंग पूर्ण है; और यह उपयोगकर्ता के पेड़ की व्याख्या करने, इसे संशोधित करने आदि के लिए है।

+7

+1 उदाहरण के लिए उदाहरण –

+8

+1 वास्तव में यह दिखाने के लिए कि क्या टोकनिंग – alex

+0

+1 उत्तर देने (दुर्घटना) के लिए +1 है एचटीएमएल/एक्सएमएल/एसजीएमएल आधारित भाषाओं में टेक्स्ट के किस टुकड़े टोकन का गठन करना चाहिए, इस बारे में दीर्घकालिक प्रश्न! (मैंने इसके बारे में अन्य धागे में पूछा।) धन्यवाद, आदमी! वास्तव में बहुत अच्छा उदाहरण! :-) – SasQ

8

parsing HTML5 पर W3C के नोट्स को याद न करें।

स्कैनिंग/लीक्सिंग के लिए एक दिलचस्प परिचय के लिए, तालिका-संचालित स्कैनर की कुशल जनरेशन के लिए वेब पर खोजें। यह दिखाता है कि अंतिम रूप से स्कैनिंग को ऑटोटाटा सिद्धांत द्वारा कैसे संचालित किया जाता है। नियमित अभिव्यक्तियों का संग्रह एक NFA में बदल दिया गया है। राज्य परिवर्तनों को निर्धारित करने के लिए एनएफए को DFA में बदल दिया गया है। पेपर फिर डीएफए को एक संक्रमण तालिका में बदलने के लिए एक विधि का वर्णन करता है।

एक महत्वपूर्ण बिंदु: स्कैनर नियमित अभिव्यक्ति सिद्धांत का उपयोग करते हैं लेकिन संभवतः मौजूदा नियमित अभिव्यक्ति पुस्तकालयों का उपयोग नहीं करते हैं। बेहतर प्रदर्शन के लिए, राज्य संक्रमणों को विशाल केस स्टेटमेंट या संक्रमण तालिका में कोडित किया जाता है।

स्कैनर गारंटी देते हैं कि सही शब्द (टोकन) का उपयोग किया जाता है। पार्सर्स गारंटी देते हैं कि शब्दों को सही संयोजन और क्रम में उपयोग किया जाता है। स्कैनर नियमित अभिव्यक्ति और ऑटोमाटा सिद्धांत का उपयोग करते हैं। पार्सर्स व्याकरण सिद्धांत का उपयोग करते हैं, खासकर context-free grammars

एक जोड़े को पार्स संसाधन:

+0

+1 धन्यवाद। यह एक सूचनात्मक (और लंबे) पढ़ने की तरह दिखता है! – alex

+0

और, यदि आपका वाक्यविन्यास भविष्य में नहीं बदलेगा, तो आप अपनी संक्रमण तालिका को सीधे स्रोत कोड में "सेंकना" कर सकते हैं और इसे एक बार संकलित कर सकते हैं। यह संभव है क्योंकि जिस मशीन पर आप अपना प्रोग्राम चला रहे हैं वह वास्तव में एक राज्य automaton भी है! तो आप "हार्डवेयर में अपने automaton को लागू कर सकते हैं"। यहां बताया गया है: राज्य कोड में स्थिति (सीपीयू में निर्देश सूचक) द्वारा प्रतिनिधित्व किया जा सकता है। राज्य संक्रमण केवल (संयुक्त) सशर्त कूद (शाखाएं) हैं। आप राज्य (प्रक्रिया कॉल और रिटर्न) को संग्रहीत/बहाल करने के लिए प्रोग्राम के ढेर का भी उपयोग कर सकते हैं। यह चीजों को बहुत तेज करेगा। – SasQ

6

HTML और XML वाक्यविन्यास (और SGML पर आधारित अन्य) काफी पार्स करने के लिए कड़ी मेहनत कर रहे हैं और वे में अच्छी तरह से फिट नहीं है lexing परिदृश्य, क्योंकि वे नियमित नहीं हैं। पार्सिंग सिद्धांत में, नियमित व्याकरण वह है जिसमें कोई भी रिकर्सन नहीं है, यानी, स्वयं के समान, घोंसले वाले पैटर्न, या कोष्ठक जैसी रैपर जो एक-दूसरे से मेल खाते हैं। लेकिन एचटीएमएल/एक्सएमएल/एसजीएमएल आधारित भाषाओं घोंसला पैटर्न है: टैग घोंसला जा सकता है। चॉम्स्की के वर्गीकरण में घोंसले पैटर्न के साथ सिंटेक्स उच्च स्तर पर है: यह संदर्भ-मुक्त या संदर्भ-निर्भर भी है।

लेकिन वापस lexer के बारे में अपने प्रश्न का:
प्रत्येक वाक्य रचना प्रतीकों में से दो प्रकार के होते हैं: गैर टर्मिनल प्रतीकों (उन जो अन्य सिंटैक्स नियमों में तनाव कम) और टर्मिनल प्रतीकों (उन जो "परमाणु" कर रहे हैं - वे सिंटैक्स पेड़ के पत्ते हैं और किसी और चीज में नहीं खुलते हैं)। टर्मिनल प्रतीक अक्सर टोकन होते हैं। टोकन को लेक्सर से एक करके पंप किया जाता है और उनके संबंधित टर्मिनल प्रतीकों से मेल खाता है।

उन टर्मिनल प्रतीकों (टोकन) अक्सर नियमित वाक्यविन्यास होते हैं, जो पहचानना आसान होता है (और यही कारण है कि यह लेक्सर के लिए फैक्टर है, जो नियमित व्याकरण के लिए अधिक विशिष्ट है और इसे अधिक सामान्य दृष्टिकोण का उपयोग करके तेज़ी से कर सकता है गैर नियमित व्याकरण)।

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

लेकिन ऊपर रयान ने इन भागों को पहचानने में बहुत अच्छा काम किया है। उसके लिए ब्रावो उसके लिए! टोकन प्रकार निम्न हैं:

  • टैगऑपर: < लेक्समे, टैग शुरू करने के लिए उपयोग किया जाता है।
  • टैगक्लोजर: > लेक्समे, टैग समाप्त करने के लिए उपयोग किया जाता है।
  • क्लोजिंगटागमार्कर: / लेक्समे टैग बंद करने में उपयोग किया जाता है।
  • नाम: अक्षर के साथ शुरू होने वाला अक्षरांक अनुक्रम, टैग नामों और विशेषता नामों के लिए उपयोग किया जाता है।
  • मूल्य: पाठ जिसमें विभिन्न वर्णों, रिक्त स्थान इत्यादि शामिल हो सकते हैं। विशेषताओं के मानों के लिए उपयोग किया जाता है।
  • बराबर: = lexeme, विशेषता मानों को उनके मानों से अलग करने के लिए उपयोग किया जाता है।
  • उद्धरण: ' lexeme, विशेषता मान संलग्न करने के लिए उपयोग किया जाता है।
  • डबलक्वाइट: " लेक्समे, विशेषता मान संलग्न करने के लिए उपयोग किया जाता है।
  • प्लेनटेक्स्ट: किसी भी पाठ में < वर्ण शामिल नहीं है और ऊपर दिए गए प्रकारों द्वारा कवर नहीं किया गया है।

आप &nbsp; या &amp; जैसे इकाई संदर्भों के लिए कुछ टोकन भी प्राप्त कर सकते हैं। शायद:

  • EntityReference: कुछ अक्षरांकीय अक्षर द्वारा पीछा किया और ; साथ समाप्त हो गया & से मिलकर शब्दिम। विशेषता मान के लिए

मैं क्यों ' और " के लिए अलग से टोकन का इस्तेमाल किया और नहीं एक टोकन? चूंकि नियमित वाक्यविन्यास यह नहीं पहचान सकता कि इनमें से कौन से पात्र अनुक्रम को समाप्त कर सकते हैं - यह उस चरित्र पर निर्भर करता है जिसने इसे शुरू किया (अंतिम चरित्र को प्रारंभिक चरित्र से मेल खाना है)। यह "कोष्ठक" गैर-नियमित वाक्यविन्यास माना जाता है। इसलिए मैं इसे उच्च स्तर पर बढ़ाता हूं - पार्सर को। इन टोकन (प्रारंभ और समापन) को एक साथ मिलान करना उनका काम होगा (या बिल्कुल भी नहीं, सरल विशेषता मानों के लिए रिक्त स्थान नहीं हैं)।

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

1

इस तरह एचटीएमएल 5 पार्सर काम करता है:

This is how HTML 5 Parser works

संबंधित मुद्दे