正则表达头痛

时间:2010-08-13 00:03:03

标签: .net regex

我想为脚本引擎验证一些C#源代码。我想确保只能引用System.Math类成员。我正在尝试创建一个正则表达式,它将匹配一个点,后跟一个大写字母,后跟任意数量的单词字符,以一个不在System.Math之前的单词边界结束。

我从这开始:

(?<!Math)\.[A-Z]+[\w]*

适用于:

return Math.Max(466.89/83.449 * 5.5);  // won’t flag this
return Xath.Max(466.89/83.449 * 5.5);  // will flag this

当它没有Math之前正确匹配.Max。但是,现在我正在尝试将正则表达式扩展为包含System,我无法让它工作。

我已经尝试了正则表达式的这些排列以及更多:

((?<!System\.Math)\.[A-Z]+[\w]*)
((?<!(?<!System)\.Math)\.[A-Z]+[\w]*)
((?<!System)\.(?<!Math)\.[A-Z]+[\w]*)
((?<!System)|(?<!Math)\.[A-Z]+[\w]*)
((?<!System\.Math)|(?<!Math)\.[A-Z]+[\w]*)

使用这些陈述:

return System.Math.Max(466.89/83.449 * 5.5);
return System.Xath.Max(466.89/83.449 * 5.5);
return Xystem.Math.Max(466.89/83.449 * 5.5);

我已经尝试了所有我能想到的东西,但它总是匹配第二个元素(上面的.Math或.Xath),或者它与任何东西都不匹配。

如果有人愿意怜悯我并指出我做错了什么,我会非常感激。

提前致谢,    慧通

2 个答案:

答案 0 :(得分:2)

如果您只是在寻找示例中所说的内容,那么这个正则表达式就可以了。

^[\w\s]*?[A-Z]\w+\.[A-Z]\w+\.(?<!System\.Math\.)

它匹配除System.Math.XXX之外的所有其他呼叫,只要:a)呼叫中有两个.,b)呼叫在一行上。

return System.Math.Max(466.89/83.449 * 5.5); // no match
return System.Xath.Max(466.89/83.449 * 5.5); // match
return Xystem.Math.Max(466.89/83.449 * 5.5); // match
System.Math.Max(466.89/83.449 * 5.5);  // no match
System.Xath.Max(466.89/83.449 * 5.5);  // match
Xystem.Math.Max(466.89/83.449 * 5.5);  // match
return System.Math.Max(466.89/83.449 * 5.5); // no match
return System.Xath.Max(466.89/83.449 * 5.5); // match
return Xystem.Math.Max(466.89/83.449 * 5.5); // match
Math.Max(466.89/83.449 * 5.5);               // no match - only one '.'
System.Max.Math(466.89/83.449 * 5.5);        // match

我同意这些意见;任何正则表达式都非常脆弱,只能被视为文本编辑器类型的帮助。如果你希望它是防弹,你需要一个解析器。

答案 1 :(得分:2)

诀窍是确保你从不在任何地方开始匹配成员名称。然后,使用前瞻来查明你所看到的内容是否以System.Math.开头是一件简单的事情。试试这个正则表达式:

(?<![\w.])(?!(?:System\.)?Math\.)(?:[A-Z]\w*\.)+[A-Z]\w*\b

lookbehind确保匹配不会在单词(\w)的中间或合格成员名称(.)的中间开始。现在,如果前瞻失败,它不能只跳到下一个组件的开头(例如Math.中的System.Math.)并再试一次。这是全有或全无。

但是,如果前面没有Math.Max,则此匹配System.。你真的需要它,还是只是为全名开发正则表达式的中间步骤?

编辑:我继续前进,使System.部分可选。