代码之家  ›  专栏  ›  技术社区  ›  Cᴏʀʏ bcherry

生成regex以查找和替换无效的HTML属性

  •  1
  • Cᴏʀʏ bcherry  · 技术社区  · 15 年前

    关于这篇文章的可悲的事实是我的瑞格舞技巧很差。我最近在一个旧项目中遇到了一些代码,我真的想做些什么。这里是:

    strDocument = strDocument.Replace("font size=""1""", "font size=0.2")
    strDocument = strDocument.Replace("font size='1'", "font size=0.2")
    strDocument = strDocument.Replace("font size=1", "font size=0.2")
    strDocument = strDocument.Replace("font size=""2""", "font size=1.5")
    strDocument = strDocument.Replace("font size='2'", "font size=1.5")
    strDocument = strDocument.Replace("font size=2", "font size=1.5")
    strDocument = strDocument.Replace("font size=3", "font size=2")
    strDocument = strDocument.Replace("font size=""3""", "font size=2")
    strDocument = strDocument.Replace("font size='3'", "font size=2")
    

    我猜这里有一些简单的regex模式,我可以用它找到引用属性值的不同方法,并用有效的语法替换它们。例如,如果有人编写了如下HTML:

    <tag attribute1=value attribute2='value' />
    

    我想能很容易地把那个标签擦干净,使它看起来像

    <tag attribute1="value" attribute2="value" />
    

    我正在使用的Web应用程序有10年的历史,由于缺少引号和大量其他垃圾,有几千个验证错误,所以如果有人能帮助我,那就太好了!

    编辑:

    我试了一下(找到了一些例子),有一些东西可以用,但希望它更聪明一点:

    Dim input As String = "<tag attribute=value attribute='value' attribute=""value"" />"
    Dim test As String = "attribute=(?:(['""])(?<attribute>(?:(?!\1).)*)\1|(?<attribute>\S+))"
    Dim result As String = Regex.Replace(input, test, "attribute=""$2""")
    

    这个输出 result 正确如下:

    <tag attribute="value" attribute="value" attribute="value" />
    

    我有办法改变(简化)吗?把这个往上一点,这样我就能找到它了。 任何 属性名?

    更新:

    以下是我迄今为止根据评论得出的结论。或许可以进一步改进:

    Dim input As String = "<tag border=2 style='display: none' width=""100%"" />"
    Dim test As String = "\s*=\s*(?:(['""])(?<g1>(?:(?!\1).)*)\1|(?<g1>\S+))"
    Dim result As String = Regex.Replace(input, test, "=""$2""")
    

    产生:

    <tag border="2" style="display: none" width="100%" />
    

    还有什么建议吗?否则我想我在你的帮助下回答了我自己的问题。

    最后更新

    这是最终产品。我希望这能帮助别人!

    Imports System.Text.RegularExpressions
    
    Module Module1
    
        Sub Main()
            Dim input As String = "<tag border=2 style='display: none' width=""100%"">Some stuff""""""in between tags==="""" that could be there</tag>" & _
                "<sometag border=2 width=""100%"" /><another that=""is"" completely=""normal"">with some content, of course</another>"
    
            Console.WriteLine(ConvertMarkupAttributeQuoteType(input, "'"))
            Console.ReadKey()
        End Sub
    
        Public Function ConvertMarkupAttributeQuoteType(ByVal html As String, ByVal quoteChar As String) As String
            Dim findTags As String = "</?\w+((\s+\w+(\s*=\s*(?:"".*?""|'.*?'|[^'"">\s]+))?)+\s*|\s*)/?>"
            Return Regex.Replace(html, findTags, New MatchEvaluator(Function(m) EvaluateTag(m, quoteChar)))
        End Function
    
        Private Function EvaluateTag(ByVal match As Match, ByVal quoteChar As String) As String
            Dim attributes As String = "\s*=\s*(?:(['""])(?<g1>(?:(?!\1).)*)\1|(?<g1>[^>\s]+))"
            Return Regex.Replace(match.Value, attributes, String.Format("={0}$2{0}", quoteChar))
        End Function
    
    End Module
    

    我觉得保持标签查找器和属性修复regex彼此独立,以防将来我想改变它们各自的工作方式。感谢您的所有意见。

    5 回复  |  直到 14 年前
        1
  •  3
  •   user134146    15 年前

    使用像Tidy这样的工具怎么样( http://tidy.sourceforge.net/ )哪个可以清理HTML代码,而不是用regex自己搜索验证错误?就我的两分钱。

        2
  •  1
  •   Rorick    15 年前

    我认为最好不要把它混入单一的超级regex。我更喜欢几个步骤:

    1. 识别标签: <([^>]+)/?>
    2. 通过标记字符串迭代地用正确的属性替换错误的属性: 代替 \s+([\w]+)\s*=\s*(['"]?)(\S+)(\2) 模式与 $1="$3" (最后一句引语后有空格)。我认为.NET允许跟踪匹配的边界。它有助于避免搜索已更正的标记部分。
        3
  •  0
  •   Lazarus    15 年前

    删除“属性”一词,即

    Dim test As String = "=(?:(['""])(?<attribute>(?:(?!\1).)*)\1|(?<attribute>\S+))" 
    

    如果页面中没有其他代码(如javascript),可以找到每个“='something'”字符串。

        4
  •  0
  •   Cᴏʀʏ bcherry    15 年前

    我回答了自己的问题。请看我问题的最后更新,了解我的答案。

        5
  •  0
  •   Al.    14 年前

    最终更新(2009年8月21日)无法取代

    <font color=red size=4>

    具有

    <font color="red" size="4>"

    (在结束标记外部的第二个属性上放置结束引号)

    我将evaluatetag中的属性字符串更改为:

    Dim attributes As String = "\s*=\s*(?:('|"")(?<g1>(?:(?!\1).)*)\1|(?<g1>[^>|\s]+))"

    改变 [^>|\s] 近端。

    这将返回我期望的结果: <font color="red" size="4">

    它适用于我的一个详尽的测试案例。