C#正则表达式前瞻匹配疑问:为何输出为"10 miles daily"?
为什么我的C#正则匹配结果是"10 miles daily"?
我需要验证字符串是否满足至少6个字符长度且包含至少一个整数,编写了如下C#代码:
string text = "I want to run 10 miles daily"; string pattern = @"(?=\.*\d).{6,}"; Match match = Regex.Match(text, pattern); Console.WriteLine(match.Value);执行后输出结果为"10 miles daily",请解释该输出产生的原因。
咱们一步步拆解你的正则和匹配过程,就能搞清楚问题所在了:
1. 先拆解你写的正则表达式 (?=\.*\d).{6,}
(?=...)是正向先行断言:它的作用是检查当前位置后面的内容是否符合括号里的规则,但本身不会“吃掉”任何字符,也不会出现在最终的匹配结果里。\.*\d:这里你不小心写错了!\.是匹配小数点,*表示可以匹配0次或多次,所以这部分的意思是「0个或多个小数点,紧接着一个数字」——而不是你想要的“字符串里存在至少一个数字”。.{6,}:匹配任意字符(除了换行符)至少6次,默认是贪婪模式,也就是会尽可能匹配最长的符合条件的内容。
2. 具体的匹配过程
Regex.Match() 会从字符串的第一个字符开始,逐个位置排查,找第一个符合正则规则的匹配项:
- 从开头的
I开始检查:断言要求当前位置后面紧跟「0个/多个小数点+数字」,但后面是空格和字母,完全不满足,所以跳过这个位置。 - 一直排查到
run后面的那个位置(也就是1的前一个位置):此时断言检查当前位置后面的内容——1是数字,\.*匹配0个小数点,刚好符合\.*\d的规则,断言通过! - 接下来执行
.{6,}:从这个位置开始,贪婪地匹配至少6个字符,直接匹配到字符串末尾,得到10 miles daily——这就是第一个符合条件的匹配项,所以最终输出的就是它。
3. 顺便提下你原本的需求实现
如果你是想验证字符串「长度至少6个字符且包含至少一个整数」,正确的正则应该把断言里的\.*改成.*(.匹配任意字符,.*表示任意字符可以出现0次或多次),也就是:
string pattern = @"(?=.*\d).{6,}";
另外,如果只是做合法性验证,用Regex.IsMatch()会更直接,不需要获取具体的匹配内容:
bool isValid = Regex.IsMatch(text, @"(?=.*\d).{6,}");
内容的提问来源于stack exchange,提问作者Chandan Gupta
相关产品推荐
相关产品推荐

