VB Like运算符相邻通配符异常行为及跨平台实现差异疑问
问题背景
我在C#中使用Microsoft.VisualBasic.CompilerServices.LikeOperator,现在要迁移到不支持该类的.NET Standard 2.0。测试时发现一个异常行为:模式"foo*?bar"本应匹配以"foo"开头、"bar"结尾且中间至少有一个字符的字符串,但.NET Framework里调用LikeOperator.LikeString("foobar", "foo*?bar", CompareMethod.Text)居然返回true。而Mono 6.12.0的VB.NET实现中,这个模式正确拒绝了"foobar",显然是.NET Framework的实现存在bug。
问题原因
这是.NET Framework对LikeOperator的实现缺陷:*匹配任意数量字符(包括0个),?要求匹配单个字符,但当*和?相邻时,.NET Framework错误地让*的0长度匹配覆盖了?的单个字符要求,导致中间没有字符的"foobar"被误判为匹配。
适配.NET Standard 2.0的解决方案
既然.NET Standard 2.0不支持LikeOperator,我们可以把VB Like模式转换成等效的正则表达式,同时修正这个bug的影响:
1. 基础模式转换规则
把VB Like的通配符映射到正则:
*→.*(匹配任意长度字符,包括0)?→.(匹配单个任意字符)- 先转义正则中的特殊字符(比如
.,+,*这些),避免语法冲突
2. 针对*?的特殊修正
原模式foo*?bar要求中间至少一个字符,对应的正则不能直接用^foo.*.bar$(这会复现.NET Framework的错误逻辑),而是要确保中间至少有一个字符,所以应该用^foo.+bar$(.+匹配至少一个任意字符)。
3. 代码示例
using System.Text.RegularExpressions; bool VbLikeMatch(string input, string likePattern) { // 先转义正则特殊字符,再替换VB通配符 string regexPattern = "^" + Regex.Escape(likePattern) .Replace(@"\*", ".*") .Replace(@"\?", ".") + "$"; // 修正.NET Framework的*? bug:把.*.替换成.+,确保中间至少一个字符 regexPattern = regexPattern.Replace(@".*\.", ".+"); // 对应CompareMethod.Text的忽略大小写规则 return Regex.IsMatch(input, regexPattern, RegexOptions.IgnoreCase); } // 测试验证 bool testResult1 = VbLikeMatch("foobar", "foo*?bar"); // 返回false,符合预期 bool testResult2 = VbLikeMatch("fooxbar", "foo*?bar"); // 返回true,符合预期 bool testResult3 = VbLikeMatch("fooxyzbar", "foo*?bar"); // 返回true,符合预期
4. 扩展注意事项
如果你的模式里还有VB Like特有的语法,比如字符列表[a-z]、排除列表[!0-9],需要额外处理这些规则:
[abc]→ 直接保留为[abc](正则兼容该语法)[!abc]→ 转换为[^abc](正则的排除语法)- 范围匹配
[a-z]直接保留即可
内容的提问来源于stack exchange,提问作者Wim Coenen

