對於參數的緣故讓我們假設一個HTML解析器。解析器(例如,HTML)如何工作?
我讀過它標記爲首先,然後解析它。
標記化意味着什麼?
解析器是否每個都讀取每個字符,構建一個多維數組來存儲結構?
例如,它是否讀取<
然後開始捕獲該元素,然後一旦遇到關閉>
(屬性外部),它會被推送到某個數組堆棧上?
我很感興趣,爲了知道(我很好奇)。
如果我是通過類似HTML Purifier讀取源,將是給我的HTML是如何解析的好主意嗎?
對於參數的緣故讓我們假設一個HTML解析器。解析器(例如,HTML)如何工作?
我讀過它標記爲首先,然後解析它。
標記化意味着什麼?
解析器是否每個都讀取每個字符,構建一個多維數組來存儲結構?
例如,它是否讀取<
然後開始捕獲該元素,然後一旦遇到關閉>
(屬性外部),它會被推送到某個數組堆棧上?
我很感興趣,爲了知道(我很好奇)。
如果我是通過類似HTML Purifier讀取源,將是給我的HTML是如何解析的好主意嗎?
首先,你應該知道,解析HTML特別難看 - HTML是被標準化前寬(和發散)的使用。這導致了各種醜陋,例如標準規定某些構造不被允許,但是隨後指定這些構造所需的行爲。
前往你直接的問題:標記化大致相當於服用英語,並分解成單詞。在英語中,大多數單詞是連續的字母流,可能包括撇號,連字符等。大多數單詞被空格包圍,但是句號,問號,感嘆號等也可以表示單詞的結尾。同樣,對於HTML(或其他),您可以指定一些關於可以用這種語言構成標記(單詞)的規則。將輸入分成令牌的代碼通常稱爲詞法分析器。
至少在正常情況下,你做而不是在開始解析之前,將所有輸入分成標記。相反,解析器調用詞法分析器來獲取下一個需要的標記。當它被調用時,詞法分析器查看足夠的輸入來查找一個標記,將其提供給解析器,並且直到下一次解析器需要更多輸入時纔再對輸入進行標記。
通常,解析器的工作方式是正確的,但是(至少在典型的解析器中)它在解析語句的過程中使用堆棧,但它通常構建來表示語句一棵樹(和抽象語法樹,又名AST),而不是一個多維數組。
基礎上解析HTML的複雜性,我會儲備看着它的分析器,直到你通過一些別人看了第一。如果你四處尋找,你應該能夠找到相當數量的解析器/詞法分析器,用於像數學表達式這樣的東西,它可能更適合作爲介紹(更小,更簡單,更容易理解等)。)
符號化可以由幾個步驟,例如,如果你有這樣的HTML代碼:
<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>
標記生成器可以是字符串轉換爲顯著令牌,
丟棄空格
的平面列表(感謝,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", ">"
]
可能有多個標記化傳遞到標記列表轉換爲更高級別的令牌,如以下假設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>"
]
然後解析器轉換令牌該列表以形成樹或圖,它表示的方式是更方便的訪問源文本由程序/操縱
此時,解析完成;然後由用戶來解釋樹,修改它等。
千萬不要錯過W3C關於parsing HTML5的註釋。
有關掃描/樂視的有趣介紹,請在網上搜索桌面驅動掃描儀的高效生成。它顯示了掃描如何最終由自動機理論驅動。正則表達式集合被轉換爲一個單一的NFA。然後將NFA轉換爲DFA以確定狀態轉換。本文隨後描述了一種將DFA轉換爲轉換表的方法。
一個關鍵點:掃描儀使用正則表達式理論,但可能不使用現有的正則表達式庫。爲了獲得更好的性能,狀態轉換被編碼爲巨大的case語句或轉換表。
掃描儀保證使用正確的單詞(標記)。解析器保證這些單詞以正確的組合和順序使用。掃描儀使用正則表達式和自動機理論。解析器使用語法理論,尤其是context-free grammars。
一對夫婦解析資源:
HTML和XML語法(基於SGML等)是非常難以分析和他們不適合早已進入lexing的情況,因爲他們不是常規。在解析理論中,正則語法是沒有任何遞歸的那個,即自相似,嵌套模式或圓括號,就像包裝必須相互匹配。但基於HTML/XML/SGML的語言確實有嵌套模式:標記可以嵌套。嵌套模式的語法在喬姆斯基分類中的級別較高:它的上下文無關或甚至與上下文相關。
但是,回到你的問題有關詞法分析器:
每個語法由兩種符號的:非終端符號(那些放鬆到其他語法規則)和終端符號(那些「原子」 - 它們是語法樹的葉子,不放鬆其他任何東西)。終端符號通常只是代幣。令牌從詞法分析器中逐一抽出並與相應的終端符號匹配。
那些終端符號(標記)通常具有常規語法,這更容易識別(這就是爲什麼它被分解爲詞法分析器,這對於常規語法更加專業化,並且可以比使用更一般的方法非常規語法)。因此,要爲HTML/XML/SGML類語言編寫詞法分析器,您需要找到足夠原子和規則的語法部分,以便由詞法分析器輕鬆處理。在這裏出現問題,因爲一開始並不清楚哪些部分是這些。我長期以來一直在努力解決這個問題。
但是列瑞恩上面已經做了很好的認識這些部分。布拉沃爲他!令牌類型如下:
<
lexeme,用於啓動標籤。>
lexeme,用於結束標籤。/
lexeme用於結束標記。=
lexeme,用於從屬性值中分離屬性名稱。'
lexeme,用於封閉屬性值。"
lexeme,用於包含屬性值。<
字符的文字,不包含在上述類型中。您也可以爲實體引用設置一些標記,如
或&
。大概是:
&
其次是一些字母數字字符,並與;
結束一語義。爲什麼我對'
和"
使用單獨的標記,而不是一個標記用於屬性值?由於常規語法無法識別哪些字符應該結束序列 - 它取決於啓動它的字符(結尾字符必須與起始字符匹配)。這種「括號」被認爲是非常規的語法。所以我把它提升到一個更高的層次 - 對於解析器。將這些令牌(開始和結束)匹配在一起(或者根本沒有,對於不包含空格的簡單屬性值)是他的工作。
事後反思: 不幸的是,其中一些令牌可能只發生在其他標記內。因此需要使用詞彙上下文,畢竟這是另一個控制狀態機識別特定令牌的狀態機。這就是爲什麼我說SGML類語言不適合詞法分析的模式。
這是HTML 5分析器是如何工作的:
看http://en.wikipedia.org/wiki/Lexical_parser一個非常簡短的介紹;還請查看那裏的「解析」文章。而HTML Purifier在某種程度上就是這樣做的。 – Piskvor 2010-06-30 14:40:07
HTML Agility Pack是開源的,基於tokanizer。 http://htmlagilitypack.codeplex.com/ – Oded 2010-06-30 14:43:12
如果您可以閱讀C(ocaml,lisp),請嘗試查看yacc/lex(ocamlyacc/ocamllex,cl-yacc/cl-lex ...)上的一些教程。您將從代碼中快速瞭解基礎知識。如果你可以閱讀代碼。 – Amadan 2010-06-30 14:48:40