一、量词:告诉引擎"要重复多少次"
量词出现在一个"单元"后面,表示这个单元要重复多少次。
单元可以是:
- 一个普通字符:
a - 一个字符类:
\d、[A-Z] - 一个分组:
(ab)
1. 常见量词一览
?:0 或 1 次*:0 次或多次+:1 次或多次{n}:恰好 n 次{n,}:至少 n 次{n,m}:n 到 m 次之间
示例:
csharp
using System.Text.RegularExpressions;
string pattern = @"^\d{3,5}$";
bool ok = Regex.IsMatch("1234", pattern); // True
2. 量词是作用在"前一项"上的
注意:ab+ 只会把 + 作用到 b 上:
- 模式:
ab+- 匹配:"ab"、"abb"、"abbbb"...
- 模式:
(ab)+- 匹配:"ab"、"abab"、"ababab"...
也就是说,当你想对一"串"东西使用量词,一定要用括号分组。
二、贪婪 vs 懒惰:* 和 *? 的根本区别
量词在默认情况下是"贪婪"的:
- 在不影响匹配成功的前提下,尽可能多地吃字符。
1. 贪婪匹配:.*
csharp
string input = "<tag>content</tag><tag>more</tag>";
string pattern = @"<tag>.*</tag>";
Match m = Regex.Match(input, pattern);
Console.WriteLine(m.Value);
匹配结果:
text
<tag>content</tag><tag>more</tag>
.*会尽可能多地吃字符,直到最后一个满足条件的</tag>。
2. 懒惰匹配:.*?
在量词后面再加一个 ?,就变成"懒惰"(即最多满足一次):
*?:尽可能少的 0 次或多次+?:尽可能少的 1 次或多次??:尽可能少的 0 或 1 次{n,m}?:在 n~m 之间,尽量少
改写上面的例子:
csharp
string pattern = @"<tag>.*?</tag>";
Match m = Regex.Match(input, pattern);
Console.WriteLine(m.Value);
匹配结果:
text
<tag>content</tag>
三、用量词写几个常见"格式":
1. 简单日期:yyyy-MM-dd
regex
^\d{4}-\d{2}-\d{2}$
- 不考虑合法性,只看格式
2. 用户名:字母开头,后面 3~15 位字母数字下划线
regex
^[A-Za-z]\w{3,15}$
[A-Za-z]:首字符必须是字母\w{3,15}:后面 3~15 个字母数字下划线- 总长度:4~16
C#:
csharp
string pattern = @"^[A-Za-z]\w{3,15}$";
bool ok = Regex.IsMatch("User_001", pattern);
3. 整数和小数
简单版本的"非负整数或小数":
regex
^\d+(\.\d+)?$
\d+:至少一位数字(\.\d+)?:可选的小数部分(.+ 至少一位数字)
匹配:0、123、3.14、0.5 不匹配:.、.5、3.(如果你想放宽,可以调整)。
四、锚点:决定"匹配的是不是整串"
锚点(Anchor)是一类特殊的"零宽"匹配,只匹配"位置",不消耗字符。
1)^:开头,$:结尾
默认情况下:
^匹配字符串的开头;$匹配字符串的结尾。
示例:
regex
^abc // 匹配以 "abc" 开头的字符串
abc$ // 匹配以 "abc" 结尾的字符串
^abc$ // 字符串只能是 "abc"
csharp
Regex.IsMatch("abc123", @"^abc"); // True
Regex.IsMatch("123abc", @"abc$"); // True
Regex.IsMatch("xabcx", @"^abc$"); // False
2. 表单校验一定要写 ^ 和 $
csharp
// 不严谨
Regex.IsMatch("abc2025-12-18xyz", @"\d{4}-\d{2}-\d{2}");
// True,只要"包含"符合格式的子串就通过
// 严谨
Regex.IsMatch("abc2025-12-18xyz", @"^\d{4}-\d{2}-\d{2}$");
// False,整个字符串不是完整日期
3. 字符类里的 ^ 意义完全不同
regex
^abc // 锚点:开头
[^abc] // 取反:匹配任何不是a、b、c的字符
^在[]外:开头锚点^在[]里且在首位:表示"取反",方括号内的字符任意组合的反面
五、单词边界:\b
\b 是"单词边界"(word boundary),匹配"从一个 \w 字符到一个非 \w 字符的边界"。
例子:
csharp
string text = "cat scat category";
string pattern = @"\bcat\b";
MatchCollection matches = Regex.Matches(text, pattern);
foreach (Match m in matches)
{
Console.WriteLine(m.Value);
}
输出:
text
cat
解析:
"cat"前后都是边界(左边是开头,右边是空格),满足\b。"scat"中的cat左边是s,属于\w,不会被\bcat\b匹配。"category"中的cat右边是e,也是\w,也不符合。
六、多行模式(Multiline)与单行模式(Singleline)
C# 中用 RegexOptions 可以控制 ^ / $ 和 . 的行为。
1. RegexOptions.Multiline:多行模式
默认情况:
csharp
string text = "first\nsecond\nthird";
string pattern = @"^second$";
Console.WriteLine(Regex.IsMatch(text, pattern)); // False
因为:
^和$在默认模式下只匹配整个字符串起始和结尾,不会感知行。
多行模式开启后:
csharp
bool ok = Regex.IsMatch(
text,
pattern,
RegexOptions.Multiline
);
Console.WriteLine(ok); // True
此时:
^/$会匹配每一行的开头/结尾(以\n作为换行)。
2. RegexOptions.Singleline:单行模式 / DOTALL
默认情况下:
.不匹配换行符。
csharp
string text = "line1\nline2";
string pattern = @".*";
Match m1 = Regex.Match(text, pattern);
Console.WriteLine(m1.Value); // "line1"
开启 Singleline 后:
csharp
Match m2 = Regex.Match(text, pattern, RegexOptions.Singleline);
Console.WriteLine(m2.Value); // "line1\nline2"
此时:
.会匹配包括换行在内的任何字符。
总结一下:
Multiline:影响^/$,让它们感知"行"Singleline:影响.,让.能匹配换行
它们可以一起用:
csharp
var regex = new Regex(
pattern,
RegexOptions.Multiline | RegexOptions.Singleline
);
结语
点个赞,关注我获取更多实用 C# 技术干货!如果觉得有用,记得收藏本文