如何用正则表达式(lex & yacc)移除HTML条件注释并保留最终标签?
解决HTML条件注释匹配与提取问题(适配Lex & Yacc)
首先得说,你之前用的正则<!(.*?)-->失效很正常——HTML条件注释的特殊结构,尤其是那种针对高版本IE的<!--[if gt IE 8]><!-->写法,会被这个宽泛的正则错误拆分,根本抓不住完整的注释块。
在Lex & Yacc环境里,用状态机(Lex的状态切换)比单一正则靠谱多了,它能精准处理条件注释的特殊格式。下面给你具体的实现方案:
1. 推荐:Lex状态机方案
先在Lex里定义一个专门处理条件注释的状态,通过状态切换识别完整注释块,同时提取其中的<html>标签,最后只保留最后一个:
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> // 存储提取到的最后一个html标签 char *last_html_tag = NULL; %} %x IF_COMMENT // 定义条件注释专属状态 %% // 匹配条件注释开头,切换到注释处理状态 "<!--\[if " { BEGIN(IF_COMMENT); } // 在注释状态中,匹配并保存html标签(覆盖旧的,只留最后一个) <IF_COMMENT>"<html "([^>]*)>" { if (last_html_tag != NULL) free(last_html_tag); last_html_tag = strdup(yytext); } // 匹配条件注释结尾,切回初始状态 <IF_COMMENT>"<!\[endif\]-->" { BEGIN(INITIAL); } // 忽略注释里的其他无关内容 <IF_COMMENT>.|\n { /* 跳过即可 */ } // 非注释内容直接输出 .|\n { printf("%s", yytext); } %% int main() { yylex(); // 最后输出保留的最后一个html标签 if (last_html_tag != NULL) { printf("%s", last_html_tag); free(last_html_tag); } return 0; }
2. 备选:单一正则方案(需Lex支持非贪婪匹配)
如果你的场景必须用单一正则,适配Lex语法的完整条件注释匹配正则如下(注意转义特殊字符):
"<!--\[if "([^]]*)\]>(.|\n)*?<!\[endif\]-->"
<!--\[if:精准匹配条件注释起始,转义[避免被当作字符集([^]]*):匹配注释条件(比如lte IE 7),直到遇到]停止(.|\n)*?:非贪婪匹配注释中间所有内容(支持换行)<!\[endif\]-->:匹配注释结尾,同样转义[
⚠️ 注意:Lex默认是贪婪匹配,.*?的非贪婪特性依赖Flex等现代Lex版本,老版本可能不支持,所以还是状态机方案更稳定。
效果验证
拿你的示例HTML输入:
<!--[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]-->
处理后会输出最后一个<html>标签:
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr">
内容的提问来源于stack exchange,提问作者Sofiane
相关产品推荐
相关产品推荐

