C#与Java正则表达式完整开发指南

C#

静态方法和Regex对象两种用法
RegexOptions详解
捕获组和命名组的实战应用
高级替换技巧(MatchEvaluator)

Java

Pattern和Matcher的正确使用
编译标志详解
性能优化技巧(reset重用)
StringBuffer替换高级用法

目录

  1. 正则表达式基础
  2. C#中的正则表达式
  3. Java中的正则表达式
  4. 常用正则表达式模式
  5. 高级技巧与示例

正则表达式基础

元字符详解

元字符 说明 示例
. 匹配任意单个字符(除换行符) a.c 匹配 “abc”, “a5c”
^ 匹配字符串开始位置 ^Hello 匹配以"Hello"开头
$ 匹配字符串结束位置 end$ 匹配以"end"结尾
* 匹配前面元素0次或多次 ab*c 匹配 “ac”, “abc”, “abbc”
+ 匹配前面元素1次或多次 ab+c 匹配 “abc”, “abbc”
? 匹配前面元素0次或1次 ab?c 匹配 “ac”, “abc”
{n} 匹配前面元素恰好n次 a{3} 匹配 “aaa”
{n,} 匹配前面元素至少n次 a{2,} 匹配 “aa”, “aaa”, “aaaa”
{n,m} 匹配前面元素n到m次 a{2,4} 匹配 “aa”, “aaa”, “aaaa”
[] 字符集,匹配其中任一字符 [abc] 匹配 “a”, “b”, “c”
[^] 否定字符集 [^abc] 匹配除a,b,c外的字符
| 或运算符 cat|dog 匹配 “cat” 或 “dog”
() 分组,捕获匹配内容 (ab)+ 匹配 “ab”, “abab”
\ 转义字符 \. 匹配实际的点号

字符类

字符类 说明 等价表达式
\d 数字字符 [0-9]
\D 非数字字符 [^0-9]
\w 单词字符(字母、数字、下划线) [a-zA-Z0-9_]
\W 非单词字符 [^a-zA-Z0-9_]
\s 空白字符(空格、制表符、换行) [ \t\n\r\f\v]
\S 非空白字符 [^ \t\n\r\f\v]

贪婪与非贪婪匹配

  • 贪婪匹配(默认): 尽可能多地匹配字符
    • *, +, ?, {n,m}
  • 非贪婪匹配: 尽可能少地匹配字符
    • *?, +?, ??, {n,m}?

示例:

  • 文本: <div>content</div>
  • 贪婪: <.*> 匹配整个字符串
  • 非贪婪: <.*?> 匹配 <div></div>

C#中的正则表达式

引入命名空间

using System.Text.RegularExpressions;

基本使用方法

1. 静态方法 - 简单匹配
// 判断是否匹配
bool isMatch = Regex.IsMatch("Hello123", @"\d+");
Console.WriteLine(isMatch); // True

// 查找匹配
Match match = Regex.Match("Hello123World456", @"\d+");
if (match.Success)
{
    Console.WriteLine(match.Value); // "123"
}

// 查找所有匹配
MatchCollection matches = Regex.Matches("Hello123World456", @"\d+");
foreach (Match m in matches)
{
    Console.WriteLine(m.Value); // "123", "456"
}

// 替换
string result = Regex.Replace("Hello123", @"\d+", "XXX");
Console.WriteLine(result); // "HelloXXX"

// 分割
string[] parts = Regex.Split("apple,banana;orange", @"[,;]");
// parts = ["apple", "banana", "orange"]
2. Regex对象 - 性能优化
// 创建Regex对象(推荐用于重复使用)
Regex regex = new Regex(@"\d+", RegexOptions.Compiled);

// 使用实例方法
bool isMatch = regex.IsMatch("Hello123");
Match match = regex.Match("Hello123");
MatchCollection matches = regex.Matches("Hello123World456");
string result = regex.Replace("Hello123", "XXX");
3. RegexOptions 选项
RegexOptions options = RegexOptions.IgnoreCase | 
                       RegexOptions.Multiline | 
                       RegexOptions.Compiled;

Regex regex = new Regex(@"pattern", options);

常用选项:

  • RegexOptions.IgnoreCase - 忽略大小写
  • RegexOptions.Multiline - 多行模式(^和$匹配行首行尾)
  • RegexOptions.Singleline - 单行模式(.匹配包括换行符)
  • RegexOptions.Compiled - 编译正则(提高性能)
  • RegexOptions.IgnorePatternWhitespace - 忽略模式中的空白

C# 实用示例

提取数字
// 提取整数
string text = "订单号:12345,金额:1000元";
Regex regex = new Regex(@"\d+");
MatchCollection matches = regex.Matches(text);
foreach (Match match in matches)
{
    Console.WriteLine(match.Value); // "12345", "1000"
}

// 提取小数
string price = "价格:¥123.45";
Match match = Regex.Match(price, @"\d+\.\d+");
Console.WriteLine(match.Value); // "123.45"

// 提取负数和小数
Regex numRegex = new Regex(@"-?\d+\.?\d*");
string text2 = "温度:-15.5度,湿度:80";
foreach (Match m in numRegex.Matches(text2))
{
    Console.WriteLine(m.Value); // "-15.5", "80"
}
提取和验证邮箱
// 验证邮箱格式
string email = "user@example.com";
bool isValid = Regex.IsMatch(email, 
    @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$");

// 提取所有邮箱
string text = "联系方式: john@example.com 或 jane@test.org";
Regex emailRegex = new Regex(@"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}");
MatchCollection emails = emailRegex.Matches(text);
foreach (Match match in emails)
{
    Console.WriteLine(match.Value);
}
捕获组的使用
// 提取日期各部分
string text = "日期: 2025-10-01";
Regex dateRegex = new Regex(@"(\d{4})-(\d{2})-(\d{2})");
Match match = dateRegex.Match(text);

if (match.Success)
{
    string year = match.Groups[1].Value;   // "2025"
    string month = match.Groups[2].Value;  // "10"
    string day = match.Groups[3].Value;    // "01"
    Console.WriteLine($"年:{year}, 月:{month}, 日:{day}");
}

// 命名捕获组
Regex namedRegex = new Regex(@"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})");
Match namedMatch = namedRegex.Match("2025-10-01");

if (namedMatch.Success)
{
    string year = namedMatch.Groups["year"].Value;
    string month = namedMatch.Groups["month"].Value;
    string day = namedMatch.Groups["day"].Value;
    Console.WriteLine($"年:{year}, 月:{month}, 日:{day}");
}
提取HTML标签内容
string html = "<div class='content'>Hello World</div><p>Test</p>";

// 提取标签名和内容
Regex tagRegex = new Regex(@"<(?<tag>\w+)[^>]*>(?<content>.*?)</\k<tag>>");
MatchCollection matches = tagRegex.Matches(html);

foreach (Match match in matches)
{
    string tag = match.Groups["tag"].Value;
    string content = match.Groups["content"].Value;
    Console.WriteLine($"标签:{tag}, 内容:{content}");
}
// 输出: 标签:div, 内容:Hello World
//       标签:p, 内容:Test
替换高级用法
// 使用MatchEvaluator进行复杂替换
string text = "价格: 100元, 数量: 5个";
Regex regex = new Regex(@"\d+");

string result = regex.Replace(text, match =>
{
    int num = int.Parse(match.Value);
    return (num * 2).ToString(); // 所有数字翻倍
});
Console.WriteLine(result); // "价格: 200元, 数量: 10个"

// 使用替换组
string phoneText = "电话: 13812345678";
string masked = Regex.Replace(phoneText, 
    @"(\d{3})\d{4}(\d{4})", 
    "$1****$2");
Console.WriteLine(masked); // "电话: 138****5678"

Java中的正则表达式

引入类库

import java.util.regex.Pattern;
import java.util.regex.Matcher;

基本使用方法

1. 静态方法 - 简单匹配
// 判断是否匹配
boolean isMatch = Pattern.matches("\\d+", "12345");
System.out.println(isMatch); // true

// 注意: Java字符串中\需要转义为\\
String regex = "\\d+";  // 等同于C#的 @"\d+"
2. Pattern和Matcher对象
// 创建Pattern对象
Pattern pattern = Pattern.compile("\\d+");

// 创建Matcher对象
Matcher matcher = pattern.matcher("Hello123World456");

// 查找匹配
if (matcher.find()) {
    System.out.println(matcher.group()); // "123"
    System.out.println("开始位置: " + matcher.start()); // 5
    System.out.println("结束位置: " + matcher.end());   // 8
}

// 查找所有匹配
while (matcher.find()) {
    System.out.println(matcher.group());
}

// 重置matcher以重新匹配
matcher.reset();

// 替换
String result = matcher.replaceAll("XXX");
System.out.println(result); // "HelloXXXWorldXXX"

// 替换第一个匹配
String resultFirst = matcher.replaceFirst("XXX");
System.out.println(resultFirst); // "HelloXXXWorld456"
3. Pattern编译标志
// 使用标志
Pattern pattern = Pattern.compile("pattern", 
    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

// 或使用内嵌标志
Pattern pattern2 = Pattern.compile("(?i)(?m)pattern");

常用标志:

  • Pattern.CASE_INSENSITIVE - 忽略大小写
  • Pattern.MULTILINE - 多行模式
  • Pattern.DOTALL - 点号匹配所有字符(包括换行)
  • Pattern.UNICODE_CASE - Unicode大小写匹配
  • Pattern.COMMENTS - 允许注释和空白

Java 实用示例

提取数字
// 提取所有整数
String text = "订单号:12345,金额:1000元";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);

while (matcher.find()) {
    System.out.println(matcher.group()); // "12345", "1000"
}

// 提取小数
String price = "价格:¥123.45";
Pattern decimalPattern = Pattern.compile("\\d+\\.\\d+");
Matcher decimalMatcher = decimalPattern.matcher(price);

if (decimalMatcher.find()) {
    System.out.println(decimalMatcher.group()); // "123.45"
}

// 提取负数和小数
Pattern numPattern = Pattern.compile("-?\\d+\\.?\\d*");
String text2 = "温度:-15.5度,湿度:80";
Matcher numMatcher = numPattern.matcher(text2);

while (numMatcher.find()) {
    System.out.println(numMatcher.group()); // "-15.5", "80"
}
提取和验证邮箱
// 验证邮箱格式
String email = "user@example.com";
String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
boolean isValid = Pattern.matches(emailRegex, email);
System.out.println("邮箱有效: " + isValid);

// 提取所有邮箱
String text = "联系方式: john@example.com 或 jane@test.org";
Pattern emailPattern = Pattern.compile(
    "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
Matcher emailMatcher = emailPattern.matcher(text);

while (emailMatcher.find()) {
    System.out.println(emailMatcher.group());
}
捕获组的使用
// 提取日期各部分
String text = "日期: 2025-10-01";
Pattern datePattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher dateMatcher = datePattern.matcher(text);

if (dateMatcher.find()) {
    String fullMatch = dateMatcher.group(0); // "2025-10-01"
    String year = dateMatcher.group(1);      // "2025"
    String month = dateMatcher.group(2);     // "10"
    String day = dateMatcher.group(3);       // "01"
    
    System.out.println(String.format("年:%s, 月:%s, 日:%s", 
        year, month, day));
}

// 命名捕获组
Pattern namedPattern = Pattern.compile(
    "(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})");
Matcher namedMatcher = namedPattern.matcher("2025-10-01");

if (namedMatcher.find()) {
    String year = namedMatcher.group("year");
    String month = namedMatcher.group("month");
    String day = namedMatcher.group("day");
    
    System.out.println(String.format("年:%s, 月:%s, 日:%s", 
        year, month, day));
}
提取HTML标签内容
String html = "<div class='content'>Hello World</div><p>Test</p>";

// 提取标签名和内容
Pattern tagPattern = Pattern.compile(
    "<(?<tag>\\w+)[^>]*>(?<content>.*?)</\\k<tag>>");
Matcher tagMatcher = tagPattern.matcher(html);

while (tagMatcher.find()) {
    String tag = tagMatcher.group("tag");
    String content = tagMatcher.group("content");
    System.out.println("标签:" + tag + ", 内容:" + content);
}
// 输出: 标签:div, 内容:Hello World
//       标签:p, 内容:Test
分割字符串
// 使用Pattern.split()
String text = "apple,banana;orange:grape";
Pattern splitPattern = Pattern.compile("[,;:]");
String[] parts = splitPattern.split(text);

for (String part : parts) {
    System.out.println(part);
}
// 输出: apple, banana, orange, grape

// 使用String.split() (内部使用Pattern)
String[] parts2 = text.split("[,;:]");
替换高级用法
// 简单替换
String text = "价格: 100元, 数量: 5个";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);

String result = matcher.replaceAll("XXX");
System.out.println(result); // "价格: XXX元, 数量: XXX个"

// 使用Matcher.appendReplacement进行复杂替换
StringBuffer sb = new StringBuffer();
matcher.reset(); // 重置matcher

while (matcher.find()) {
    int num = Integer.parseInt(matcher.group());
    matcher.appendReplacement(sb, String.valueOf(num * 2));
}
matcher.appendTail(sb);
System.out.println(sb.toString()); // "价格: 200元, 数量: 10个"

// 使用替换组
String phoneText = "电话: 13812345678";
String masked = phoneText.replaceAll(
    "(\\d{3})\\d{4}(\\d{4})", 
    "$1****$2");
System.out.println(masked); // "电话: 138****5678"
边界匹配
// 单词边界
String text = "cat catch category";
Pattern wordPattern = Pattern.compile("\\bcat\\b");
Matcher wordMatcher = wordPattern.matcher(text);

while (wordMatcher.find()) {
    System.out.println(wordMatcher.group()); // 只匹配 "cat"
}

// 行首行尾(需要MULTILINE模式)
String multiLineText = "Line1\nLine2\nLine3";
Pattern linePattern = Pattern.compile("^Line", Pattern.MULTILINE);
Matcher lineMatcher = linePattern.matcher(multiLineText);

int count = 0;
while (lineMatcher.find()) {
    count++;
}
System.out.println("匹配行数: " + count); // 3

常用正则表达式模式

数字匹配

整数:              ^\d+$ 或 ^[0-9]+$
正整数:            ^[1-9]\d*$
负整数:            ^-[1-9]\d*$
整数(包括正负):    ^-?\d+$

小数:              ^\d+\.\d+$
正小数:            ^[1-9]\d*\.\d+|0\.\d*[1-9]\d*$
负小数:            ^-([1-9]\d*\.\d+|0\.\d*[1-9]\d*)$
浮点数:            ^-?\d+\.?\d*$

科学计数法:        ^-?\d+\.?\d*[eE][+-]?\d+$

示例代码 (C#):

// 验证整数
bool isInteger = Regex.IsMatch("12345", @"^\d+$");

// 验证小数(保留2位)
bool isDecimal = Regex.IsMatch("123.45", @"^\d+\.\d{2}$");

// 提取所有数字(包括小数)
string text = "价格:¥123.45,数量:10";
MatchCollection numbers = Regex.Matches(text, @"-?\d+\.?\d*");

示例代码 (Java):

// 验证整数
boolean isInteger = Pattern.matches("^\\d+$", "12345");

// 验证小数(保留2位)
boolean isDecimal = Pattern.matches("^\\d+\\.\\d{2}$", "123.45");

// 提取所有数字(包括小数)
String text = "价格:¥123.45,数量:10";
Pattern pattern = Pattern.compile("-?\\d+\\.?\\d*");
Matcher matcher = pattern.matcher(text);

字符串匹配

英文字母:          ^[a-zA-Z]+$
小写字母:          ^[a-z]+$
大写字母:          ^[A-Z]+$
字母和数字:        ^[a-zA-Z0-9]+$
字母数字下划线:    ^\w+$

中文字符:          ^[\u4e00-\u9fa5]+$
中英文数字:        ^[\u4e00-\u9fa5a-zA-Z0-9]+$

不包含特殊字符:    ^[a-zA-Z0-9\u4e00-\u9fa5]+$

示例代码 (C#):

// 验证只包含字母
bool isAlpha = Regex.IsMatch("HelloWorld", @"^[a-zA-Z]+$");

// 验证中文
bool isChinese = Regex.IsMatch("你好世界", @"^[\u4e00-\u9fa5]+$");

// 提取所有中文
string text = "Hello你好World世界";
MatchCollection chinese = Regex.Matches(text, @"[\u4e00-\u9fa5]+");

示例代码 (Java):

// 验证只包含字母
boolean isAlpha = Pattern.matches("^[a-zA-Z]+$", "HelloWorld");

// 验证中文
boolean isChinese = Pattern.matches("^[\\u4e00-\\u9fa5]+$", "你好世界");

// 提取所有中文
String text = "Hello你好World世界";
Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher matcher = pattern.matcher(text);

日期和时间

日期 YYYY-MM-DD:   ^\d{4}-\d{2}-\d{2}$
日期 YYYY/MM/DD:   ^\d{4}/\d{2}/\d{2}$
日期 DD-MM-YYYY:   ^\d{2}-\d{2}-\d{4}$

时间 HH:MM:        ^([01]\d|2[0-3]):[0-5]\d$
时间 HH:MM:SS:     ^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$

日期时间:          ^\d{4}-\d{2}-\d{2}\s+([01]\d|2[0-3]):[0-5]\d:[0-5]\d$
ISO 8601:          ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$

示例代码 (C#):

// 验证日期格式
string datePattern = @"^\d{4}-\d{2}-\d{2}$";
bool isValidDate = Regex.IsMatch("2025-10-01", datePattern);

// 提取日期各部分
string text = "会议时间: 2025-10-01 14:30:00";
Match match = Regex.Match(text, 
    @"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})\s+(?<hour>\d{2}):(?<minute>\d{2}):(?<second>\d{2})");

if (match.Success)
{
    Console.WriteLine($"年: {match.Groups["year"].Value}");
    Console.WriteLine($"月: {match.Groups["month"].Value}");
    Console.WriteLine($"日: {match.Groups["day"].Value}");
    Console.WriteLine($"时: {match.Groups["hour"].Value}");
    Console.WriteLine($"分: {match.Groups["minute"].Value}");
    Console.WriteLine($"秒: {match.Groups["second"].Value}");
}

网络相关

IP地址:            ^(\d{1,3}\.){3}\d{1,3}$
精确IP(0-255):     ^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$

URL:               ^https?://[^\s/$.?#].[^\s]*$
域名:              ^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$

邮箱:              ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

示例代码 (C#):

// 验证邮箱
string emailPattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
bool isValidEmail = Regex.IsMatch("user@example.com", emailPattern);

// 验证URL
string urlPattern = @"^https?://[^\s/$.?#].[^\s]*$";
bool isValidUrl = Regex.IsMatch("https://www.example.com", urlPattern);

// 提取URL
string text = "访问 https://example.com 或 http://test.org";
MatchCollection urls = Regex.Matches(text, @"https?://[^\s]+");
foreach (Match match in urls)
{
    Console.WriteLine(match.Value);
}

电话号码

中国手机号:        ^1[3-9]\d{9}$
中国固话:          ^0\d{2,3}-?\d{7,8}$

美国电话:          ^\d{3}-\d{3}-\d{4}$
国际格式:          ^\+\d{1,3}\s?\d{1,14}$

示例代码 (Java):

// 验证中国手机号
String phonePattern = "^1[3-9]\\d{9}$";
boolean isValidPhone = Pattern.matches(phonePattern, "13812345678");

// 提取电话号码
String text = "联系电话: 138-1234-5678 或 010-12345678";
Pattern pattern = Pattern.compile("\\d{3}-?\\d{4}-?\\d{4}|0\\d{2,3}-?\\d{7,8}");
Matcher matcher = pattern.matcher(text);

while (matcher.find()) {
    System.out.println(matcher.group());
}

身份证号

中国身份证15位:    ^\d{15}$
中国身份证18位:    ^\d{17}[\dXx]$
通用:              ^\d{15}|\d{17}[\dXx]$

密码强度

至少8位字母数字:   ^[a-zA-Z0-9]{8,}$
必须包含大小写字母和数字:  ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$
必须包含大小写字母数字和特殊字符:  ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$

示例代码 (C#):

// 验证强密码(至少8位,包含大小写字母和数字)
string passwordPattern = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$";
bool isStrongPassword = Regex.IsMatch("MyPass123", passwordPattern);

// 检查密码强度
string CheckPasswordStrength(string password)
{
    if (Regex.IsMatch(password, @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{12,}$"))
        return "很强";
    if (Regex.IsMatch(password, @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$"))
        return "强";
    if (Regex.IsMatch(password, @"^[a-zA-Z0-9]{6,}$"))
        return "中";
    return "弱";
}

位置和边界

行首:              ^pattern
行尾:              pattern$
单词边界:          \bword\b
非单词边界:        \Bword\B

字符串开始:        \Apattern
字符串结束:        pattern\Z

环视:
  正向前瞻:        pattern(?=check)
  负向前瞻:        pattern(?!check)
  正向后顾:        (?<=check)pattern
  负向后顾:        (?<!check)pattern

示例代码 (C#):

// 匹配单词边界
string text = "cat catch category";
MatchCollection matches = Regex.Matches(text, @"\bcat\b");
// 只匹配独立的 "cat",不匹配 "catch" 和 "category"

// 正向前瞻: 匹配后面跟着 "bar" 的 "foo"
string text2 = "foobar foobaz";
MatchCollection matches2 = Regex.Matches(text2, @"foo(?=bar)");
// 只匹配 "foobar" 中的 "foo"

// 负向前瞻: 匹配后面不跟 "bar" 的 "foo"
MatchCollection matches3 = Regex.Matches(text2, @"foo(?!bar)");
// 只匹配 "foobaz" 中的 "foo"

// 正向后顾: 匹配前面是 "USD" 的数字
string price = "USD100 EUR200 USD150";
MatchCollection matches4 = Regex.Matches(price, @"(?<=USD)\d+");
// 匹配 "100" 和 "150"

示例代码 (Java):

// 匹配行首的特定单词(多行模式)
String text = "Hello World\nHello Java\nGoodbye World";
Pattern pattern = Pattern.compile("^Hello", Pattern.MULTILINE);
Matcher matcher = pattern.matcher(text);

while (matcher.find()) {
    System.out.println("找到行首的Hello,位置: " + matcher.start());
}

// 环视示例
String text2 = "100美元 200欧元 300美元";
Pattern pattern2 = Pattern.compile("(?<=\\d{3})美元");
Matcher matcher2 = pattern2.matcher(text2);
// 匹配前面是三位数字的"美元"

高级技巧与示例

1. 命名捕获组和反向引用

C#:

// 查找重复的单词
string text = "the the cat sat sat on the mat";
Regex regex = new Regex(@"\b(?<word>\w+)\s+\k<word>\b");
MatchCollection matches = regex.Matches(text);

foreach (Match match in matches)
{
    Console.WriteLine($"重复单词: {match.Groups["word"].Value}");
}
// 输出: the, sat

// HTML标签匹配(确保开闭标签一致)
string html = "<div>content</div><span>text</span>";
Regex tagRegex = new Regex(@"<(?<tag>\w+)>.*?</\k<tag>>");

Java:

// 查找重复的单词
String text = "the the cat sat sat on the mat";
Pattern pattern = Pattern.compile("\\b(?<word>\\w+)\\s+\\k<word>\\b");
Matcher matcher = pattern.matcher(text);

while (matcher.find()) {
    System.out.println("重复单词: " + matcher.group("word"));
}

2. 贪婪与非贪婪匹配实战

C#:

string html = "<div>First</div><div>Second</div>";

// 贪婪匹配
Match greedyMatch = Regex.Match(html, @"<div>.*</div>");
Console.WriteLine(greedyMatch.Value);
// 输出: <div>First</div><div>Second</div>

// 非贪婪匹配
MatchCollection lazyMatches = Regex.Matches(html, @"<div>.*?</div>");
foreach (Match match in lazyMatches)
{
    Console.WriteLine(match.Value);
}
// 输出: <div>First</div>
//       <div>Second</div>

3. 性能优化技巧

C#:

// 1. 使用编译选项提高重复使用的性能
Regex compiled = new Regex(@"\d+", RegexOptions.Compiled);

// 2. 重用Regex对象
Regex reusable = new Regex(@"pattern");
for (int i = 0; i < 1000; i++)
{
    reusable.IsMatch(texts[i]); // 比每次new Regex快得多
}

// 3. 使用静态缓存(Regex内部自动缓存最近15个)
bool match = Regex.IsMatch(text, @"pattern"); // 会被缓存

// 4. 限制回溯(使用原子组或占有量词)
// 不好: ^.*(\d+)$ 可能导致大量回溯
// 好:   ^.*?(\d+)$ 或 ^[^\d]*(\d+)$

Java:

// 1. 重用Pattern对象
Pattern pattern = Pattern.compile("\\d+");
for (int i = 0; i < 1000; i++) {
    Matcher matcher = pattern.matcher(texts[i]);
    matcher.find();
}

// 2. 使用Matcher.reset()重用Matcher对象
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("");

for (String text : texts) {
    matcher.reset(text);
    while (matcher.find()) {
        // 处理匹配
    }
}

// 3. 避免复杂的回溯
// 使用原子组: (?>...)
// 使用占有量词: *+, ++, ?+

4. 复杂数据提取示例

C#完整示例 - 日志解析:

string logText = @"
[2025-10-01 14:30:15] INFO: User login successful - UserID: 12345
[2025-10-01 14:35:22] ERROR: Database connection failed - Code: 500
[2025-10-01 14:40:10] WARN: Memory usage high - 85%
";

string logPattern = @"\[(?<date>\d{4}-\d{2}-\d{2})\s+(?<time>\d{2}:\d{2}:\d{2})\]\s+(?<level>\w+):\s+(?<message>.+)";
Regex logRegex = new Regex(logPattern);

MatchCollection logMatches = logRegex.Matches(logText);

foreach (Match match in logMatches)
{
    Console.WriteLine($"日期: {match.Groups["date"].Value}");
    Console.WriteLine($"时间: {match.Groups["time"].Value}");
    Console.WriteLine($"级别: {match.Groups["level"].Value}");
    Console.WriteLine($"消息: {match.Groups["message"].Value}");
    Console.WriteLine("---");
}

Java完整示例 - JSON简单解析:

String jsonText = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}";

// 提取键值对
Pattern kvPattern = Pattern.compile("\"(?<key>\\w+)\":\"?(?<value>[^,}\"]+)\"?");
Matcher kvMatcher = kvPattern.matcher(jsonText);

Map<String, String> jsonMap = new HashMap<>();
while (kvMatcher.find()) {
    String key = kvMatcher.group("key");
    String value = kvMatcher.group("value");
    jsonMap.put(key, value);
    System.out.println(key + " = " + value);
}

5. 实用工具方法

C# 工具类:

public static class RegexHelper
{
    // 验证邮箱
    public static bool IsValidEmail(string email)
    {
        return Regex.IsMatch(email, 
            @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$");
    }
    
    // 验证手机号
    public static bool IsValidPhone(string phone)
    {
        return Regex.IsMatch(phone, @"^1[3-9]\d{9}$");
    }
    
    // 提取所有数字
    public static List<string> ExtractNumbers(string text)
    {
        MatchCollection matches = Regex.Matches(text, @"-?\d+\.?\d*");
        return matches.Cast<Match>().Select(m => m.Value).ToList();
    }
    
    // 移除HTML标签
    public static string RemoveHtmlTags(string html)
    {
        return Regex.Replace(html, @"<[^>]+>", "");
    }
    
    // 驼峰转下划线
    public static string CamelToSnake(string camelCase)
    {
        return Regex.Replace(camelCase, 
            @"([a-z])([A-Z])", 
            "$1_$2").ToLower();
    }
}

Java 工具类:

public class RegexHelper {
    
    // 验证邮箱
    public static boolean isValidEmail(String email) {
        return Pattern.matches(
            "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", 
            email);
    }
    
    // 验证手机号
    public static boolean isValidPhone(String phone) {
        return Pattern.matches("^1[3-9]\\d{9}$", phone);
    }
    
    // 提取所有数字
    public static List<String> extractNumbers(String text) {
        List<String> numbers = new ArrayList<>();
        Pattern pattern = Pattern.compile("-?\\d+\\.?\\d*");
        Matcher matcher = pattern.matcher(text);
        
        while (matcher.find()) {
            numbers.add(matcher.group());
        }
        return numbers;
    }
    
    // 移除HTML标签
    public static String removeHtmlTags(String html) {
        return html.replaceAll("<[^>]+>", "");
    }
    
    // 驼峰转下划线
    public static String camelToSnake(String camelCase) {
        return camelCase.replaceAll("([a-z])([A-Z])", "$1_$2")
                       .toLowerCase();
    }
}

常见陷阱与注意事项

1. 转义字符差异

C#: 使用 @ 字符串前缀避免双重转义

string pattern = @"\d+";  // 推荐
string pattern2 = "\\d+"; // 也可以,但不推荐

Java: 必须双重转义

String pattern = "\\d+";  // 必须
String pattern2 = "\d+";  // 错误!

2. 性能陷阱

// 灾难性回溯示例(避免!)
^(a+)+$
^(a*)*$
^(a|a)*$

// 对输入 "aaaaaaaaaaaaaaaaaab" 会导致指数级回溯

// 改进方案
^a+$
^a*$

3. 点号不匹配换行符

// 默认情况下 . 不匹配换行符
// 使用 Singleline (Java中是DOTALL) 选项
Regex regex = new Regex(@"<div>.*?</div>", RegexOptions.Singleline);
Pattern pattern = Pattern.compile("<div>.*?</div>", Pattern.DOTALL);

4. Unicode支持

// C# 默认支持Unicode
Regex regex = new Regex(@"[\u4e00-\u9fa5]+"); // 中文字符
// Java 需要启用UNICODE_CASE等标志
Pattern pattern = Pattern.compile(
    "[\\u4e00-\\u9fa5]+", 
    Pattern.UNICODE_CASE);

总结与最佳实践

1. 基本原则

  • 优先使用简单明确的模式
  • 避免过度使用正则表达式(某些情况字符串方法更合适)
  • 充分测试边界情况

2. 性能考虑

  • 重用编译后的Regex/Pattern对象
  • 避免灾难性回溯
  • 使用非贪婪匹配时考虑性能影响

3. 可维护性

  • 使用注释模式说明复杂正则表达式
  • 使用命名捕获组提高可读性
  • 将常用正则提取为常量

4. 安全性

  • 验证用户输入时使用严格的正则
  • 注意ReDoS攻击(正则拒绝服务)
  • 不要使用正则处理HTML/XML(使用专门的解析器)

5. 调试工具

  • Regex101.com - 在线测试和调试
  • RegExr.com - 可视化正则表达式
  • IDE内置的正则测试工具

参考资源

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐