7. 复杂的正则表达式示例(续)
7.1 验证日期格式
以下正则表达式用于验证日期格式,例如YYYY-MM-DD。
import java.util.regex.*;
public class RegexExample {
public static void main(String[] args) {
String[] dates = {
"2023-01-01",
"2023-13-01", // 无效月份
"2023-12-32", // 无效日期
"2023-02-29", // 非闰年的无效日期
"2024-02-29" // 闰年的有效日期
};
String patternString = "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$";
Pattern pattern = Pattern.compile(patternString);
for (String date : dates) {
Matcher matcher = pattern.matcher(date);
System.out.println(date + ": " + matcher.matches());
}
}
}
在上述代码中,正则表达式^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$
用于验证日期格式。该表达式验证了年份的格式为四位数字,月份为01到12,日期为01到31。
8. 正则表达式的高级用法
8.1 捕获组和非捕获组
捕获组通过圆括号()
来定义,非捕获组通过(?:...)
来定义。捕获组会保存匹配到的内容,而非捕获组不会。
import java.util.regex.*;
public class RegexExample {
public static void main(String[] args) {
String text = "The price is $123.45";
String patternString = "(\\$)(\\d+\\.\\d{2})";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println("Full match: " + matcher.group(0)); // 输出:$123.45
System.out.println("Currency symbol: " + matcher.group(1)); // 输出:$
System.out.println("Amount: " + matcher.group(2)); // 输出:123.45
}
}
}
在上述代码中,正则表达式(\\$)(\\d+\\.\\d{2})
用于匹配带有货币符号的金额。捕获组用于提取货币符号和金额部分。
8.2 断言
断言是一种零宽度匹配,分为正向断言和负向断言。
- • 正向断言
(?=...)
:匹配某个位置前面满足特定条件的字符。 - • 负向断言
(?!...)
:匹配某个位置前面不满足特定条件的字符。
import java.util.regex.*;
public class RegexExample {
public static void main(String[] args) {
String text = "foo123bar";
// 正向断言:匹配数字前面是foo的部分
String patternString1 = "foo(?=\\d)";
Pattern pattern1 = Pattern.compile(patternString1);
Matcher matcher1 = pattern1.matcher(text);
if (matcher1.find()) {
System.out.println("Positive Lookahead: " + matcher1.group()); // 输出:foo
}
// 负向断言:匹配数字前面不是foo的部分
String patternString2 = "(?<!foo)\\d";
Pattern pattern2 = Pattern.compile(patternString2);
Matcher matcher2 = pattern2.matcher(text);
while (matcher2.find()) {
System.out.println("Negative Lookbehind: " + matcher2.group());
}
}
}
在上述代码中,正向断言用于匹配数字前面是foo
的部分,负向断言用于匹配数字前面不是foo
的部分。
8.3 贪婪、勉强和占有量词
量词用于指定匹配的数量,量词可以是贪婪的、勉强的或占有的。
- • 贪婪量词(默认):尽可能多地匹配。比如
*
、+
、?
。 - • 勉强量词:尽可能少地匹配。比如
*?
、+?
、??
。 - • 占有量词:尽可能多地匹配且不回溯。比如
*+
、++
、?+
。
import java.util.regex.*;
public class RegexExample {
public static void main(String[] args) {
String text = "aaaa";
// 贪婪量词:尽可能多地匹配
String patternString1 = "a+";
Pattern pattern1 = Pattern.compile(patternString1);
Matcher matcher1 = pattern1.matcher(text);
if (matcher1.find()) {
System.out.println("Greedy: " + matcher1.group()); // 输出:aaaa
}
// 勉强量词:尽可能少地匹配
String patternString2 = "a+?";
Pattern pattern2 = Pattern.compile(patternString2);
Matcher matcher2 = pattern2.matcher(text);
if (matcher2.find()) {
System.out.println("Reluctant: " + matcher2.group()); // 输出:a
}
// 占有量词:尽可能多地匹配且不回溯
String patternString3 = "a++";
Pattern pattern3 = Pattern.compile(patternString3);
Matcher matcher3 = pattern3.matcher(text);
if (matcher3.find()) {
System.out.println("Possessive: " + matcher3.group()); // 输出:aaaa
}
}
}
在上述代码中,分别演示了贪婪量词、勉强量词和占有量词的匹配行为。
9. 正则表达式的性能优化
正则表达式的性能可能会受到匹配模式和输入数据的影响。在编写正则表达式时,应该考虑以下优化策略:
9.1 避免回溯
使用贪婪量词可能导致回溯,从而影响性能。尽量使用勉强量词或占有量词来减少回溯。
9.2 使用预编译的Pattern
避免在每次匹配时都重新编译正则表达式。可以将正则表达式预编译成Pattern
对象并重用。
public class RegexExample {
private static final Pattern pattern = Pattern.compile("\\d+");
public static void main(String[] args) {
String text = "123 456 789";
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println("Found: " + matcher.group());
}
}
}
9.3 优化正则表达式
简化和优化正则表达式,使其更高效。例如,使用字符类而不是单独的字符匹配。
String patternString1 = "[aeiou]"; // 使用字符类
String patternString2 = "a|e|i|o|u"; // 使用单独字符匹配
10. 常见正则表达式示例
10.1 验证IP地址
以下正则表达式用于验证IPv4地址的格式。
import java.util.regex.*;
public class RegexExample {
public static void main(String[] args) {
String[] ips = {
"192.168.0.1",
"255.255.255.255",
"256.256.256.256", // 无效IP地址
"192.168.1.300" // 无效IP地址
};
String patternString = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
Pattern pattern = Pattern.compile(patternString);
for (String ip : ips) {
Matcher matcher = pattern.matcher(ip);
System.out.println(ip + ": " + matcher.matches());
}
}
}
在上述代码中,正则表达式^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$
用于验证IPv4地址的格式。
11. 工具和框架中的正则表达式
正则表达式在各种工具和框架中得到了广泛应用。例如:
- • 文本编辑器和IDE:许多文本编辑器和IDE支持正则表达式搜索和替换。
- • Web框架:Web框架使用正则表达式进行URL路由和参数验证。
- • 数据处理工具:正则表达式用于数据清洗和解析。