为啥在这个正则表达式中左括号被转义?

Posted

技术标签:

【中文标题】为啥在这个正则表达式中左括号被转义?【英文标题】:Why is a left parenthesis being escaped in this Regex?为什么在这个正则表达式中左括号被转义? 【发布时间】:2010-09-19 09:35:08 【问题描述】:

我正在使用此处的 html 清理白名单代码:http://refactormycode.com/codes/333-sanitize-html

我需要添加“字体”标签作为附加标签来匹配,所以我尝试在<img标签检查之后添加这个条件

if (tagname.StartsWith("<font"))

    // detailed <font> tag checking
    // Non-escaped expression (for testing in a Regex editor app)
    // ^<font(\s*size="\d1")?(\s*color="((#[0-9a-f]6)|(#[0-9a-f]3)|red|green|blue|black|white)")?(\s*face="(Arial|Courier New|Garamond|Georgia|Tahoma|Verdana)")?\s*?>$
    if (!IsMatch(tagname, @"<font
                            (\s*size=""\d1"")?
                            (\s*color=""((#[0-9a-f]6)|(#[0-9a-f]3)|red|green|blue|black|white)"")?
                            (\s*face=""(Arial|Courier New|Garamond|Georgia|Tahoma|Verdana)"")?
                             \s*?>"))
    
        html = html.Remove(tag.Index, tag.Length);
    

除了上述条件之外,我的代码与我链接到的页面中的代码几乎相同。当我尝试在 C# 中对此进行测试时,它会抛出一个异常“Not enough )'s”。我数过括号数次,并通过一些基于 javascript 的在线正则表达式测试器运行表达式,但似乎没有一个告诉我任何问题。

我是否在我的正则表达式中遗漏了导致括号转义的内容?我需要做什么来解决这个问题?

更新 经过大量的试验和错误,我记得# 符号是正则表达式中的注释。解决此问题的关键是转义 # 字符。万一其他人遇到同样的问题,我已经包含了我的修复(只是转义 # 符号)

if (tagname.StartsWith("<font"))

    // detailed <font> tag checking
    // Non-escaped expression (for testing in a Regex editor app)
    // ^<font(\s*size="\d1")?(\s*color="((#[0-9a-f]6)|(#[0-9a-f]3)|red|green|blue|black|white)")?(\s*face="(Arial|Courier New|Garamond|Georgia|Tahoma|Verdana)")?\s*?>$
    if (!IsMatch(tagname, @"<font
                            (\s*size=""\d1"")?
                            (\s*color=""((\#[0-9a-f]6)|(\#[0-9a-f]3)|red|green|blue|black|white)"")?
                            (\s*face=""(Arial|Courier\sNew|Garamond|Georgia|Tahoma|Verdana)"")?
                             \s*?>"))
    
        html = html.Remove(tag.Index, tag.Length);
    

【问题讨论】:

您的更新仅适用于指定了 IgnorePatternWhitespace 选项的情况......这是我在没有回复的情况下询问的 IsMatch 代码......即您没有向我们展示导致问题的代码。 顺便说一句:您的正则表达式不会匹配具有不同顺序属性的字体标签,例如 属性没有以不同的顺序匹配,我很好。我使用的 HTML 编辑器控件只会按照我测试的顺序生成 标记。 【参考方案1】:

您的 IsMatch 方法使用选项 RegexOptions.IgnorePatternWhitespace,它允许您将 cmets 放入正则表达式中,因此您必须对 # 字符进行转义,否则它将被解释为注释。

if (!IsMatch(tagname,@"<font(\s*size=""\d1"")?
    (\s*color=""((\#[0-9a-f]6)|(\#[0-9a-f]3)|red|green|blue|black|white)"")?
    (\s*face=""(Arial|Courier New|Garamond|Georgia|Tahoma|Verdana)"")?
    \s?>"))

    html = html.Remove(tag.Index, tag.Length);

【讨论】:

【参考方案2】:

我看不出正则表达式有什么明显错误。我会尝试通过删除部分正则表达式来隔离问题,直到问题消失,然后专注于导致问题的部分。

【讨论】:

我不确定这与正则表达式有什么关系——它对我来说很好【参考方案3】:

对我来说很好用...您使用的是什么版本的 .NET 框架,exact 异常是什么?

另外 - 你的 IsMatch 方法是什么样的?这只是传递给Regex.IsMatch 的途径吗?

[update] 问题是 OP 的示例代码没有显示他们正在使用 IgnorePatternWhitespace 正则表达式选项;使用此选项不起作用;没有这个选项(即如所示),代码很好。

【讨论】:

【参考方案4】:

下载 Chris Sells Regex Designer。它是测试 .NET 正则表达式的绝佳免费工具。

我不确定这个正则表达式是否会做你想要的,因为它取决于与你在正则表达式中的属性匹配的属性的顺序。例如,如果 face="Arial" 先于 size="5",则 face= 将不匹配。

您的正则表达式中存在一些转义问题。您需要使用\ 转义您的" 您需要使用\ 转义您的# 您需要在Courier New 中使用\s 而不仅仅是空格。您需要使用RegexOptions.IgnorePatternWhitespaceRegexOptions.IgnoreCase options

<font
(\s+size=\"\d1\")?
(\s+color=\"((\#[0-9a-f]6)|(\#[0-9a-f]3)|red|green|blue|black|white)\")?
(\s+face=\"(Arial|Courier\sNew|Garamond|Georgia|Tahoma|Verdana)\")?

# 字符是导致异常的原因,缺少一些误导性的 ) 消息。

【讨论】:

属性的顺序对我来说总是相同的,因为我正在使用文本编辑器控件。我不需要因为 @ 符号而逃避我的 "。这是 "courier new" 的一个很好的捕捉。我没有看到那个。

以上是关于为啥在这个正则表达式中左括号被转义?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式知识补漏

为啥正则表达式构造函数需要双重转义?

正则表达式的艰辛路之一

js正则 变量中括号

用正则表达式不就可以让用户名不能包含一些字符了吗,为啥还要转义

正则表达式小点