2009-08-03 72 views
2

有人有正則表達式來匹配未封閉的HTML標記嗎?正則表達式用於未封閉的HTML標記

<i><b>test<i>ing</i> 

是對正則表達式這樣太複雜:例如,正則表達式將在<b>和第二<i>,但不是第一<i>或第一的收盤</i>標籤相匹配?可能需要一些遞歸的,程序化的處理?

回答

6

我敢肯定,一些正則表達式的大師可以拼湊一些近似解決方案的東西,但這是一個壞主意:HTML isn't regular。考慮一個能夠識別這些問題的HTML解析器,或者自己解析它。

+3

太糟糕了SO沒有API。我想象的是:for(問題q:questionsTagged(「regex」,「html」)){q.addAnswer(new Answer(「HTML不規則,所以正則表達式幾乎不是一個好的選擇。「);}` – 2009-08-03 18:08:45

2

是的它需要遞歸處理,並且可能很深(當然是一個奇特的循環),它不會用正則表達式來完成。你可以製作一個深度處理幾個級別的正則表達式,但不能用於任何HTML文件。這是因爲解析器必須記住流中任何給定點處打開了哪些標記,而正則表達式並不擅長。

對某些計數器使用SAX解析器,或者使用彈出/推入的堆棧來保持您的狀態。想想如何編碼這個遊戲來查看我對html標籤深度的意思。 http://en.wikipedia.org/wiki/Tower_of_Hanoi

1

正如@Pesto說的,HTML不規則,你將不得不建立HTML語法規則,並遞歸應用它們。

如果您希望以編程方式修復HTML,我使用了一個名爲html tidy的組件,取得了相當的成功。對於大多數語言(COM +,Dotnet,PHP等),都有它的構建。

如果你只是需要手動修復它,我會推薦一個好的IDE。 Visual Studio 2008做得很好,最新的Dreamweaver也做得很好。

1

不,這對於正則表達式來說很複雜。你的問題相當於測試正確使用括號的算術表達式,它至少需要pushdown automaton才能成功。

對於您的情況,您應該在打開標記,關閉標記和文本節點(例如使用正則表達式)中分割HTML代碼。將結果存儲在一個列表中。然後,您可以遍歷節點列表並將每個開始標記推入堆棧。如果在節點列表中遇到結束標記,則必須檢查最上面的堆棧條目是否是同一類型的開始標記。否則,您會發現您查找的html語法錯誤。

1

我有一個案例,我處理單一自包含行的我am。以下正則表達式適用於我:<[^/]+$,它與「<」匹配,然後是不是「/」的任何內容。

0

我建議使用Nokogiri

 
    Nokogiri::HTML::DocumentFragment.parse(html).to_html 
1

您可以使用正則表達式來識別所有的HTML開始/結束元素,然後用棧枚舉,推新的元素,和流行的結束標記。在C#中試試這個 -

public static bool ValidateHtmlTags(string html) 
{ 
    string expr = "(<([a-zA-Z]+)\\b[^>]*>)|(</([a-zA-Z]+) *>)"; 
    Regex regex = new Regex(expr, RegexOptions.IgnoreCase); 
    var stack = new Stack<Tuple<string, string>>(); 
    var result = new StringBuilder(); 
    bool valid = true; 

    foreach (Match match in regex.Matches(html)) 
    { 
     string element = match.Value; 
     string beginTag = match.Groups[2].Value; 
     string endTag = match.Groups[4].Value; 

     if (beginTag == "") 
     { 
      string previousTag = stack.Peek().Item1; 
      if (previousTag == endTag) 
       stack.Pop(); 
      else 
      { 
       valid = false; 
       break; 
      } 
     } 
     else if (!element.EndsWith("/>")) 
     { 
      // Write more informative message here if desired 
      string message = string.Format("Char({0})", match.Index); 
      stack.Push(new Tuple<string, string>(beginTag, message)); 
     } 
    } 

    if (stack.Count > 0) 
     valid = false; 

    // Alternative return stack.Peek().Item2 for more informative message 
    return valid; 
}