首页 > 解决方案 > How to remove all conditional HTML comments?

问题描述

How to remove all HTML conditional comments using regular expressions (lex & yacc) ? I want to remove all that comments and leave only the last HTML tag.

I have tried this Regex "<!"(.*?)--> to get the conditional comments but it didn't work, I am looking for a Regex that matches with theses conditional comments.

"<!"(.*?)-->

Here is the HTML code below : I am trying to delete all the comments and to leave only the last HTML tag.

<!--[if lte IE 7]> 

    <html class="ie7 oldie" xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr"> 

<![endif]-->


<!--[if IE 8]> 

    <html class="ie8 oldie" xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr"> 

<![endif]-->


<!--[if gt IE 8]><!--> 
    <html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr"> 
<!--<![endif]-->

标签: htmlregexflex-lexerlex

解决方案


以下是关于 (f)lex 正则表达式的两个重要事实。(有关 Flex 模式的完整文档,请参阅flex 手册。该部分不是很长。)

  1. 在 (f)lex 中,.通配符匹配除换行符之外的任何内容。换句话说,它等价于[^\n]。所以"<!".*只会匹配到行尾。您可以通过使用(.|\n)来解决此问题,但请参见下文。

  2. (F)lex 不提供非贪婪重复 ( *?)。所有重复都延伸到尽可能长的匹配。(.*?)-->因此将匹配到最后-->一行,并且(.|\n)*?-->匹配到-->文件中的最后一个。

可以编写一个正则表达式来执行您想要的操作,尽管它有点混乱:

<!--([^-]|-[^-]|--+[^->])*--+>

应该可以工作,只要输入文本不以未终止的注释结尾。(您的模式中的引号是不必要的,因为引用的字符对 (f)lex 没有任何特殊含义,但它们不会受到伤害。我将它们排除在外是因为我认为它们不会导致模式不那么可读.)

重复的序列匹配任何一个:

  • then 以外的一个字符-;或者
  • A-后面跟着其他东西-;或者
  • 两个或更多-后跟>.

重复中的最后一个选择可能需要一些解释。潜在的问题是避免输入问题,例如

<!-- Comment with two many dashes --->

如果我们只是将 tempting--[^>]作为第三种选择,--->将不会被识别为终止模式,因为---会匹配--[^>](破折号不是直角括号)然后>会匹配[^-],并且扫描将继续。添加+以匹配更长的破折号序列是不够的,因为与许多正则表达式引擎一样,(f)lex 正在寻找最长的整体匹配,而不是每组备选方案中最长的子匹配。所以我们需要写--+[^->],不能匹配---

如果不清楚——我可以明白为什么不会——,您可以改用开始条件来编写一组更简单的模式:

%x COMMENT
%%
"<!--"    { BEGIN(COMMENT); }
<COMMENT>{
   "-->"   { BEGIN(INITIAL); }
   [^-]+   ;
   .|\n    ;
}

第二条<COMMENT>规则实际上只是一种效率技巧。它避免了对每个角色触发无操作动作。有了第二条规则,最后一条规则真的只能匹配一个-,所以它可以这样写。但是完整地编写它可以让您删除第二条规则并向自己证明没有它它也可以工作。

在这样的片段中匹配注释的关键在于 (f)lex 总是选择最长的匹配,这在某些方面类似于非贪婪匹配的目标。在<COMMENT>开始条件内,-如果它不能是匹配的一部分,则只会匹配单个字符后备规则-->,后者更长。


推荐阅读