|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
正则表达式是文本处理的强大工具,它提供了一种灵活、高效的方式来匹配、查找和替换文本。对于Java开发者而言,掌握正则表达式技巧可以大大提升文本处理能力,无论是数据验证、日志分析还是文本提取,正则表达式都能发挥重要作用。本文将从基础语法开始,逐步深入到高级应用,帮助Java开发者全面掌握正则表达式匹配技巧。
正则表达式基础语法
字符类
字符类是正则表达式中最基本的构建块,用于匹配特定类型的字符。
- // 示例:使用字符类
- import java.util.regex.*;
- public class CharacterClassExample {
- public static void main(String[] args) {
- // 匹配任意一个小写字母
- System.out.println("a".matches("[a-z]")); // true
- System.out.println("A".matches("[a-z]")); // false
-
- // 匹配任意一个字母(不区分大小写)
- System.out.println("a".matches("[a-zA-Z]")); // true
- System.out.println("Z".matches("[a-zA-Z]")); // true
-
- // 匹配任意一个数字
- System.out.println("5".matches("[0-9]")); // true
- System.out.println("a".matches("[0-9]")); // false
-
- // 匹配非数字
- System.out.println("a".matches("[^0-9]")); // true
- System.out.println("5".matches("[^0-9]")); // false
-
- // 预定义字符类
- System.out.println("5".matches("\\d")); // true,等同于[0-9]
- System.out.println("a".matches("\\D")); // true,等同于[^0-9]
- System.out.println(" ".matches("\\s")); // true,空白字符
- System.out.println("a".matches("\\S")); // true,非空白字符
- System.out.println("a".matches("\\w")); // true,单词字符[a-zA-Z_0-9]
- System.out.println("#".matches("\\W")); // true,非单词字符
- }
- }
复制代码
量词
量词用于指定前面的字符或字符组出现的次数。
- // 示例:使用量词
- import java.util.regex.*;
- public class QuantifierExample {
- public static void main(String[] args) {
- // ? 表示0次或1次
- System.out.println("color".matches("colou?r")); // true
- System.out.println("colour".matches("colou?r")); // true
-
- // * 表示0次或多次
- System.out.println("ab".matches("ab*c")); // false
- System.out.println("ac".matches("ab*c")); // true
- System.out.println("abbc".matches("ab*c")); // true
-
- // + 表示1次或多次
- System.out.println("ac".matches("ab+c")); // false
- System.out.println("abc".matches("ab+c")); // true
- System.out.println("abbc".matches("ab+c")); // true
-
- // {n} 表示恰好n次
- System.out.println("abbbbc".matches("ab{4}c")); // true
- System.out.println("abbbc".matches("ab{4}c")); // false
-
- // {n,} 表示至少n次
- System.out.println("abbbbc".matches("ab{3,}c")); // true
- System.out.println("abbbc".matches("ab{3,}c")); // true
- System.out.println("abbc".matches("ab{3,}c")); // false
-
- // {n,m} 表示至少n次,最多m次
- System.out.println("abbbbc".matches("ab{3,5}c")); // true
- System.out.println("abbbbbbbc".matches("ab{3,5}c")); // false
- }
- }
复制代码
边界匹配
边界匹配用于匹配字符串的边界位置,而不是实际字符。
- // 示例:边界匹配
- import java.util.regex.*;
- public class BoundaryExample {
- public static void main(String[] args) {
- // ^ 匹配行开始
- System.out.println("hello world".matches("^hello.*")); // true
- System.out.println("say hello".matches("^hello.*")); // false
-
- // $ 匹配行结束
- System.out.println("hello world".matches(".*world$")); // true
- System.out.println("world hello".matches(".*world$")); // false
-
- // \b 匹配单词边界
- Pattern pattern = Pattern.compile("\\bhello\\b");
- Matcher matcher1 = pattern.matcher("hello world");
- Matcher matcher2 = pattern.matcher("helloworld");
- System.out.println(matcher1.find()); // true
- System.out.println(matcher2.find()); // false
-
- // \B 匹配非单词边界
- pattern = Pattern.compile("\\Bhello\\B");
- matcher1 = pattern.matcher("helloworld");
- matcher2 = pattern.matcher("hello world");
- System.out.println(matcher1.find()); // true
- System.out.println(matcher2.find()); // false
- }
- }
复制代码
分组和捕获
分组使用括号()将多个字符组合为一个单元,并可以捕获匹配的内容。
- // 示例:分组和捕获
- import java.util.regex.*;
- public class GroupingExample {
- public static void main(String[] args) {
- // 基本分组
- Pattern pattern = Pattern.compile("(\\d{3})-(\\d{2})-(\\d{4})");
- Matcher matcher = pattern.matcher("123-45-6789");
-
- if (matcher.find()) {
- System.out.println("完整匹配: " + matcher.group(0)); // 123-45-6789
- System.out.println("第一组: " + matcher.group(1)); // 123
- System.out.println("第二组: " + matcher.group(2)); // 45
- System.out.println("第三组: " + matcher.group(3)); // 6789
- }
-
- // 非捕获分组 (?:...)
- pattern = Pattern.compile("(?:\\d{3})-(\\d{2})-(\\d{4})");
- matcher = pattern.matcher("123-45-6789");
-
- if (matcher.find()) {
- System.out.println("完整匹配: " + matcher.group(0)); // 123-45-6789
- System.out.println("第一组: " + matcher.group(1)); // 45
- System.out.println("第二组: " + matcher.group(2)); // 6789
- }
- }
- }
复制代码
Java中的正则表达式API
Pattern类
Pattern类是正则表达式的编译表示,它没有公共构造方法,必须通过调用其静态方法compile()来创建实例。
- // 示例:Pattern类的基本使用
- import java.util.regex.*;
- public class PatternExample {
- public static void main(String[] args) {
- // 编译正则表达式
- Pattern pattern = Pattern.compile("\\d+");
-
- // 获取正则表达式字符串
- System.out.println("正则表达式: " + pattern.pattern());
-
- // 分割字符串
- String[] result = pattern.split("one1two2three3four4");
- for (String s : result) {
- System.out.println(s);
- }
-
- // 带限制的分割
- result = pattern.split("one1two2three3four4", 3);
- for (String s : result) {
- System.out.println(s);
- }
-
- // 获取标志
- Pattern caseInsensitivePattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
- System.out.println("标志: " + caseInsensitivePattern.flags());
- }
- }
复制代码
Matcher类
Matcher类是执行匹配操作的引擎,通过Pattern对象的matcher()方法创建。
- // 示例:Matcher类的基本使用
- import java.util.regex.*;
- public class MatcherExample {
- public static void main(String[] args) {
- Pattern pattern = Pattern.compile("\\d+");
- Matcher matcher = pattern.matcher("one1two2three3four4");
-
- // 查找所有匹配
- while (matcher.find()) {
- System.out.println("找到匹配: " + matcher.group() +
- " 位置: " + matcher.start() +
- " 到 " + matcher.end());
- }
-
- // 尝试匹配整个字符串
- matcher.reset();
- System.out.println("整个字符串匹配: " + matcher.matches());
-
- // 尝试匹配字符串开头
- matcher.reset();
- System.out.println("字符串开头匹配: " + matcher.lookingAt());
-
- // 替换操作
- matcher.reset();
- String result = matcher.replaceAll("#");
- System.out.println("替换所有数字: " + result);
-
- matcher.reset();
- result = matcher.replaceFirst("#");
- System.out.println("替换第一个数字: " + result);
- }
- }
复制代码
常用方法
- // 示例:正则表达式常用方法
- import java.util.regex.*;
- public class CommonMethodsExample {
- public static void main(String[] args) {
- // String类中的正则方法
- String text = "Hello, this is a test string with 123 numbers.";
-
- // 检查是否匹配
- System.out.println("字符串是否包含数字: " + text.matches(".*\\d+.*"));
-
- // 分割字符串
- String[] words = text.split("\\s+");
- System.out.println("分割后的单词数: " + words.length);
- for (String word : words) {
- System.out.println(word);
- }
-
- // 替换
- String replaced = text.replaceAll("\\s+", "_");
- System.out.println("替换空格后: " + replaced);
-
- // 替换第一个匹配
- replaced = text.replaceFirst("\\s+", "_");
- System.out.println("替换第一个空格后: " + replaced);
-
- // 使用Pattern和Matcher进行更复杂的操作
- Pattern pattern = Pattern.compile("\\b(\\w+)(\\s+)(\\1)\\b");
- Matcher matcher = pattern.matcher("hello hello world world test");
-
- // 查找重复单词
- while (matcher.find()) {
- System.out.println("找到重复单词: " + matcher.group(1) +
- " 位置: " + matcher.start() +
- " 到 " + matcher.end());
- }
- }
- }
复制代码
实用匹配技巧
邮箱验证
- // 示例:邮箱验证
- import java.util.regex.*;
- public class EmailValidation {
- public static void main(String[] args) {
- // 基本邮箱验证正则
- String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
-
- String[] testEmails = {
- "user@example.com",
- "user.name@example.com",
- "user-name@example.com",
- "user_name@example.com",
- "user+name@example.com",
- "user@sub.example.com",
- "user@example.co.uk",
- "invalid.email@com",
- "@example.com",
- "user@.com",
- "user@example.",
- "user..name@example.com"
- };
-
- Pattern pattern = Pattern.compile(emailRegex);
-
- for (String email : testEmails) {
- Matcher matcher = pattern.matcher(email);
- System.out.println(email + " 是有效的邮箱: " + matcher.matches());
- }
- }
- }
复制代码
电话号码验证
- // 示例:电话号码验证
- import java.util.regex.*;
- public class PhoneNumberValidation {
- public static void main(String[] args) {
- // 美国电话号码格式验证
- String usPhoneRegex = "^(\\+1\\s?)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$";
-
- // 国际电话号码格式验证(简化版)
- String internationalPhoneRegex = "^(\\+\\d{1,3}\\s?)?\\(?\\d{1,4}\\)?[\\s.-]?\\d{1,4}[\\s.-]?\\d{1,4}[\\s.-]?\\d{1,9}$";
-
- String[] testPhones = {
- "1234567890",
- "123-456-7890",
- "(123) 456-7890",
- "+1 123 456 7890",
- "+1 (123) 456-7890",
- "+44 20 7946 0958",
- "+86 10 1234 5678",
- "123", // 无效
- "12345678901234567890" // 无效
- };
-
- Pattern usPattern = Pattern.compile(usPhoneRegex);
- Pattern internationalPattern = Pattern.compile(internationalPhoneRegex);
-
- System.out.println("美国电话号码验证:");
- for (String phone : testPhones) {
- Matcher matcher = usPattern.matcher(phone);
- System.out.println(phone + " 是有效的美国电话号码: " + matcher.matches());
- }
-
- System.out.println("\n国际电话号码验证:");
- for (String phone : testPhones) {
- Matcher matcher = internationalPattern.matcher(phone);
- System.out.println(phone + " 是有效的国际电话号码: " + matcher.matches());
- }
- }
- }
复制代码
URL解析
- // 示例:URL解析
- import java.util.regex.*;
- public class URLParsing {
- public static void main(String[] args) {
- // URL解析正则表达式
- String urlRegex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
-
- // 更详细的URL解析正则,用于提取各部分
- String detailedUrlRegex = "^(https?|ftp|file)://([^/:]+)(?::(\\d+))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?$";
-
- String[] testUrls = {
- "https://www.example.com",
- "http://example.com:8080/path/to/resource?query=value#fragment",
- "ftp://files.example.com/documents",
- "file:///C:/path/to/file.txt",
- "invalid-url"
- };
-
- Pattern pattern = Pattern.compile(urlRegex);
- Pattern detailedPattern = Pattern.compile(detailedUrlRegex);
-
- System.out.println("URL有效性验证:");
- for (String url : testUrls) {
- Matcher matcher = pattern.matcher(url);
- System.out.println(url + " 是有效的URL: " + matcher.matches());
- }
-
- System.out.println("\n详细URL解析:");
- for (String url : testUrls) {
- Matcher matcher = detailedPattern.matcher(url);
- if (matcher.matches()) {
- System.out.println("URL: " + url);
- System.out.println("协议: " + matcher.group(1));
- System.out.println("主机: " + matcher.group(2));
- System.out.println("端口: " + (matcher.group(3) != null ? matcher.group(3) : "默认"));
- System.out.println("路径: " + matcher.group(4));
- System.out.println("查询字符串: " + (matcher.group(5) != null ? matcher.group(5) : "无"));
- System.out.println("片段: " + (matcher.group(6) != null ? matcher.group(6) : "无"));
- System.out.println();
- }
- }
- }
- }
复制代码
HTML标签处理
- // 示例:HTML标签处理
- import java.util.regex.*;
- public class HTMLTagProcessing {
- public static void main(String[] args) {
- String html = "<div class="example">\n" +
- " <p>This is a <b>sample</b> text with <a href="https://example.com">links</a>.</p>\n" +
- " <ul>\n" +
- " <li>Item 1</li>\n" +
- " <li>Item 2</li>\n" +
- " </ul>\n" +
- "</div>";
-
- // 提取所有HTML标签
- Pattern tagPattern = Pattern.compile("<[^>]+>");
- Matcher tagMatcher = tagPattern.matcher(html);
-
- System.out.println("提取的HTML标签:");
- while (tagMatcher.find()) {
- System.out.println(tagMatcher.group());
- }
-
- // 提取特定标签及其内容
- Pattern pPattern = Pattern.compile("<p>(.*?)</p>", Pattern.DOTALL);
- Matcher pMatcher = pPattern.matcher(html);
-
- System.out.println("\n<p>标签及其内容:");
- while (pMatcher.find()) {
- System.out.println(pMatcher.group(1));
- }
-
- // 提取链接
- Pattern linkPattern = Pattern.compile("<a\\s+href="([^"]+)"[^>]*>([^<]+)</a>");
- Matcher linkMatcher = linkPattern.matcher(html);
-
- System.out.println("\n链接及其文本:");
- while (linkMatcher.find()) {
- System.out.println("URL: " + linkMatcher.group(1) + ", 文本: " + linkMatcher.group(2));
- }
-
- // 移除所有HTML标签
- String noHtml = html.replaceAll("<[^>]+>", "");
- System.out.println("\n移除HTML标签后的文本:");
- System.out.println(noHtml);
- }
- }
复制代码
高级应用
贪婪与懒惰匹配
- // 示例:贪婪与懒惰匹配
- import java.util.regex.*;
- public class GreedyLazyMatching {
- public static void main(String[] args) {
- String text = "<div>内容1</div><div>内容2</div>";
-
- // 贪婪匹配(默认)
- Pattern greedyPattern = Pattern.compile("<div>.*</div>");
- Matcher greedyMatcher = greedyPattern.matcher(text);
-
- System.out.println("贪婪匹配:");
- while (greedyMatcher.find()) {
- System.out.println("匹配: " + greedyMatcher.group());
- }
-
- // 懒惰匹配
- Pattern lazyPattern = Pattern.compile("<div>.*?</div>");
- Matcher lazyMatcher = lazyPattern.matcher(text);
-
- System.out.println("\n懒惰匹配:");
- while (lazyMatcher.find()) {
- System.out.println("匹配: " + lazyMatcher.group());
- }
-
- // 贪婪匹配与量词
- String numbers = "1234567890";
-
- // 贪婪匹配
- Pattern greedyNumbers = Pattern.compile("\\d{5,8}");
- Matcher greedyNumMatcher = greedyNumbers.matcher(numbers);
-
- System.out.println("\n贪婪匹配数字:");
- if (greedyNumMatcher.find()) {
- System.out.println("匹配: " + greedyNumMatcher.group()); // 匹配12345678
- }
-
- // 懒惰匹配
- Pattern lazyNumbers = Pattern.compile("\\d{5,8}?");
- Matcher lazyNumMatcher = lazyNumbers.matcher(numbers);
-
- System.out.println("\n懒惰匹配数字:");
- if (lazyNumMatcher.find()) {
- System.out.println("匹配: " + lazyNumMatcher.group()); // 匹配12345
- }
- }
- }
复制代码
回溯控制
- // 示例:回溯控制
- import java.util.regex.*;
- public class BacktrackingControl {
- public static void main(String[] args) {
- // 原子组 (?>...)
- String text = "123456";
-
- // 常规分组
- Pattern normalPattern = Pattern.compile("(\\d+\\d+)");
- Matcher normalMatcher = normalPattern.matcher(text);
-
- System.out.println("常规分组:");
- if (normalMatcher.find()) {
- System.out.println("匹配: " + normalMatcher.group());
- }
-
- // 原子组
- Pattern atomicPattern = Pattern.compile("(?>\\d+\\d+)");
- Matcher atomicMatcher = atomicPattern.matcher(text);
-
- System.out.println("\n原子组:");
- if (atomicMatcher.find()) {
- System.out.println("匹配: " + atomicMatcher.group());
- }
-
- // 占有量词 (++, *+, ?+, {m,n}+)
- text = "123456";
-
- // 常规贪婪量词
- Pattern greedyPattern = Pattern.compile("\\d++6");
- Matcher greedyMatcher = greedyPattern.matcher(text);
-
- System.out.println("\n占有量词:");
- if (greedyMatcher.find()) {
- System.out.println("匹配: " + greedyMatcher.group());
- } else {
- System.out.println("没有匹配,因为\\d++占有了所有数字,没有回溯");
- }
-
- // 常规贪婪量词(会回溯)
- Pattern normalGreedyPattern = Pattern.compile("\\d+6");
- Matcher normalGreedyMatcher = normalGreedyPattern.matcher(text);
-
- System.out.println("\n常规贪婪量词(会回溯):");
- if (normalGreedyMatcher.find()) {
- System.out.println("匹配: " + normalGreedyMatcher.group());
- }
- }
- }
复制代码
零宽断言
- // 示例:零宽断言
- import java.util.regex.*;
- public class ZeroWidthAssertions {
- public static void main(String[] args) {
- String text = "I have 100 dollars and 200 euros.";
-
- // 正向先行断言 (?=...)
- Pattern positiveLookahead = Pattern.compile("\\d+(?=\\s*dollars)");
- Matcher positiveMatcher = positiveLookahead.matcher(text);
-
- System.out.println("正向先行断言(查找dollars前的数字):");
- while (positiveMatcher.find()) {
- System.out.println("匹配: " + positiveMatcher.group());
- }
-
- // 负向先行断言 (?!...)
- Pattern negativeLookahead = Pattern.compile("\\d+(?!\\s*dollars)");
- Matcher negativeMatcher = negativeLookahead.matcher(text);
-
- System.out.println("\n负向先行断言(查找不在dollars前的数字):");
- while (negativeMatcher.find()) {
- System.out.println("匹配: " + negativeMatcher.group());
- }
-
- // 正向后行断言 (?<=...)
- Pattern positiveLookbehind = Pattern.compile("(?<=I have\\s)\\d+");
- Matcher positiveBehindMatcher = positiveLookbehind.matcher(text);
-
- System.out.println("\n正向后行断言(查找'I have'后的数字):");
- while (positiveBehindMatcher.find()) {
- System.out.println("匹配: " + positiveBehindMatcher.group());
- }
-
- // 负向后行断言 (?<!...)
- Pattern negativeLookbehind = Pattern.compile("(?<!I have\\s)\\d+");
- Matcher negativeBehindMatcher = negativeLookbehind.matcher(text);
-
- System.out.println("\n负向后行断言(查找不在'I have'后的数字):");
- while (negativeBehindMatcher.find()) {
- System.out.println("匹配: " + negativeBehindMatcher.group());
- }
-
- // 复杂示例:查找单词边界但不在特定单词后
- String complexText = "The car is parked in the carpark.";
- Pattern complexPattern = Pattern.compile("\\bcar\\b(?!park)");
- Matcher complexMatcher = complexPattern.matcher(complexText);
-
- System.out.println("\n复杂示例:查找单词'car'但不后跟'park':");
- while (complexMatcher.find()) {
- System.out.println("匹配: " + complexMatcher.group() + " 位置: " + complexMatcher.start());
- }
- }
- }
复制代码
性能优化
- // 示例:正则表达式性能优化
- import java.util.regex.*;
- import java.util.concurrent.TimeUnit;
- public class PerformanceOptimization {
- public static void main(String[] args) {
- String longText = "This is a test string with many words. ".repeat(1000) + "The final word is end.";
-
- // 预编译正则表达式 vs 每次编译
- String wordPattern = "\\bword\\b";
-
- // 不预编译
- long startTime = System.nanoTime();
- for (int i = 0; i < 1000; i++) {
- Pattern pattern = Pattern.compile(wordPattern);
- Matcher matcher = pattern.matcher(longText);
- while (matcher.find()) {
- // 什么都不做,只是匹配
- }
- }
- long endTime = System.nanoTime();
- System.out.println("不预编译正则表达式耗时: " +
- TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
-
- // 预编译
- Pattern precompiledPattern = Pattern.compile(wordPattern);
- startTime = System.nanoTime();
- for (int i = 0; i < 1000; i++) {
- Matcher matcher = precompiledPattern.matcher(longText);
- while (matcher.find()) {
- // 什么都不做,只是匹配
- }
- }
- endTime = System.nanoTime();
- System.out.println("预编译正则表达式耗时: " +
- TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
-
- // 使用具体字符类代替通配符
- String testString = "abc123def456ghi789";
-
- // 使用通配符
- Pattern dotPattern = Pattern.compile(".+");
- startTime = System.nanoTime();
- for (int i = 0; i < 10000; i++) {
- Matcher matcher = dotPattern.matcher(testString);
- matcher.matches();
- }
- endTime = System.nanoTime();
- System.out.println("\n使用通配符耗时: " +
- TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
-
- // 使用具体字符类
- Pattern specificPattern = Pattern.compile("[a-z0-9]+");
- startTime = System.nanoTime();
- for (int i = 0; i < 10000; i++) {
- Matcher matcher = specificPattern.matcher(testString);
- matcher.matches();
- }
- endTime = System.nanoTime();
- System.out.println("使用具体字符类耗时: " +
- TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
-
- // 避免回溯
- String backtrackTest = "<div>content</div><div>more content</div>";
-
- // 可能导致回溯的模式
- Pattern backtrackPattern = Pattern.compile("<div>.*</div>");
- startTime = System.nanoTime();
- for (int i = 0; i < 10000; i++) {
- Matcher matcher = backtrackPattern.matcher(backtrackTest);
- matcher.find();
- }
- endTime = System.nanoTime();
- System.out.println("\n可能导致回溯的模式耗时: " +
- TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
-
- // 避免回溯的模式
- Pattern noBacktrackPattern = Pattern.compile("<div>[^<]*</div>");
- startTime = System.nanoTime();
- for (int i = 0; i < 10000; i++) {
- Matcher matcher = noBacktrackPattern.matcher(backtrackTest);
- matcher.find();
- }
- endTime = System.nanoTime();
- System.out.println("避免回溯的模式耗时: " +
- TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + " ms");
- }
- }
复制代码
常见问题与解决方案
处理特殊字符
- // 示例:处理正则表达式中的特殊字符
- import java.util.regex.*;
- public class SpecialCharacters {
- public static void main(String[] args) {
- // 需要转义的特殊字符
- String specialChars = ".^$*+?{}[]\\|()";
-
- // 使用Pattern.quote()方法自动转义
- String quotedText = Pattern.quote("1.5 * 2 = 3");
- System.out.println("转义后的字符串: " + quotedText);
-
- // 匹配包含特殊字符的文本
- String text = "The price is $19.99.";
- String regex = "The price is \\$\\d+\\.\\d+\\.";
-
- Pattern pattern = Pattern.compile(regex);
- Matcher matcher = pattern.matcher(text);
-
- if (matcher.matches()) {
- System.out.println("匹配成功: " + matcher.group());
- }
-
- // 使用Matcher.quoteReplacement()处理替换字符串中的特殊字符
- String input = "Replace $1 with $2";
- String replacement = Matcher.quoteReplacement("$$100 and $$200");
-
- Pattern replacePattern = Pattern.compile("\\$(\\d)");
- Matcher replaceMatcher = replacePattern.matcher(input);
-
- String result = replaceMatcher.replaceAll(replacement);
- System.out.println("替换结果: " + result);
- }
- }
复制代码
多行模式与单行模式
- // 示例:多行模式与单行模式
- import java.util.regex.*;
- public class MultilineDotallModes {
- public static void main(String[] args) {
- String text = "First line\nSecond line\nThird line";
-
- // 默认模式(^和$匹配整个字符串的开始和结束)
- Pattern defaultPattern = Pattern.compile("^First.*line$");
- Matcher defaultMatcher = defaultPattern.matcher(text);
-
- System.out.println("默认模式匹配: " + defaultMatcher.find());
-
- // 多行模式(^和$匹配每行的开始和结束)
- Pattern multilinePattern = Pattern.compile("^First.*line$", Pattern.MULTILINE);
- Matcher multilineMatcher = multilinePattern.matcher(text);
-
- System.out.println("多行模式匹配: " + multilineMatcher.find());
-
- // 单行模式(.匹配包括换行符在内的所有字符)
- String html = "<div>\nContent\n</div>";
-
- // 默认模式
- Pattern defaultDotPattern = Pattern.compile("<div>.*</div>");
- Matcher defaultDotMatcher = defaultDotPattern.matcher(html);
-
- System.out.println("\n默认模式匹配HTML: " + defaultDotMatcher.find());
-
- // 单行模式(DOTALL)
- Pattern dotallPattern = Pattern.compile("<div>.*</div>", Pattern.DOTALL);
- Matcher dotallMatcher = dotallPattern.matcher(html);
-
- System.out.println("单行模式匹配HTML: " + dotallMatcher.find());
-
- // 组合使用多行和单行模式
- String complexText = "Start\nLine 1\nLine 2\nEnd";
-
- Pattern combinedPattern = Pattern.compile("^Start.*End$", Pattern.MULTILINE | Pattern.DOTALL);
- Matcher combinedMatcher = combinedPattern.matcher(complexText);
-
- System.out.println("\n组合模式匹配: " + combinedMatcher.find());
- }
- }
复制代码
Unicode支持
- // 示例:Unicode支持
- import java.util.regex.*;
- public class UnicodeSupport {
- public static void main(String[] args) {
- // Unicode字符匹配
- String text = "English 中文 日本語 한국어 Español Français";
-
- // 匹配中文字符
- Pattern chinesePattern = Pattern.compile("[\\u4e00-\\u9fff]+");
- Matcher chineseMatcher = chinesePattern.matcher(text);
-
- System.out.println("中文字符:");
- while (chineseMatcher.find()) {
- System.out.println(chineseMatcher.group());
- }
-
- // 匹配日文字符(平假名和片假名)
- Pattern japanesePattern = Pattern.compile("[\\u3040-\\u309f\\u30a0-\\u30ff]+");
- Matcher japaneseMatcher = japanesePattern.matcher(text);
-
- System.out.println("\n日文字符:");
- while (japaneseMatcher.find()) {
- System.out.println(japaneseMatcher.group());
- }
-
- // 匹配韩文字符
- Pattern koreanPattern = Pattern.compile("[\\uac00-\\ud7af]+");
- Matcher koreanMatcher = koreanPattern.matcher(text);
-
- System.out.println("\n韩文字符:");
- while (koreanMatcher.find()) {
- System.out.println(koreanMatcher.group());
- }
-
- // 使用Unicode属性(需要UNICODE_CHARACTER_CLASS标志)
- Pattern letterPattern = Pattern.compile("\\p{L}+", Pattern.UNICODE_CHARACTER_CLASS);
- Matcher letterMatcher = letterPattern.matcher(text);
-
- System.out.println("\n所有字母(使用Unicode属性):");
- while (letterMatcher.find()) {
- System.out.println(letterMatcher.group());
- }
-
- // 使用Unicode脚本
- Pattern hanPattern = Pattern.compile("\\p{Han}+", Pattern.UNICODE_CHARACTER_CLASS);
- Matcher hanMatcher = hanPattern.matcher(text);
-
- System.out.println("\n汉字(使用Unicode脚本):");
- while (hanMatcher.find()) {
- System.out.println(hanMatcher.group());
- }
- }
- }
复制代码
最佳实践
可读性与维护性
- // 示例:提高正则表达式的可读性与维护性
- import java.util.regex.*;
- public class ReadabilityAndMaintainability {
- public static void main(String[] args) {
- // 复杂的正则表达式(难以阅读和维护)
- String complexRegex = "^(https?|ftp)://(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+(?:[A-Z]{2,6}\\.?|[A-Z0-9-]{2,}\\.?))(?::\\d{2,5})?(?:/[^\s]*)?$";
-
- // 使用注释和构建块提高可读性
- String protocol = "(https?|ftp)";
- String domain = "(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+(?:[A-Z]{2,6}\\.?|[A-Z0-9-]{2,}\\.?))";
- String port = "(?::\\d{2,5})?";
- String path = "(?:/[^\s]*)?";
-
- String readableRegex = "^" + protocol + "://" + domain + port + path + "$";
-
- // 使用COMMENTS标志允许正则表达式中的空白和注释
- String commentedRegex =
- "^" + protocol + "://" + // 协议部分
- domain + // 域名部分
- port + // 端口部分(可选)
- path + "$"; // 路径部分(可选)
-
- Pattern pattern = Pattern.compile(commentedRegex, Pattern.CASE_INSENSITIVE | Pattern.COMMENTS);
-
- String[] testUrls = {
- "https://www.example.com",
- "http://subdomain.example.com:8080/path/to/resource",
- "ftp://files.example.com/documents/"
- };
-
- for (String url : testUrls) {
- Matcher matcher = pattern.matcher(url);
- System.out.println(url + " 是有效的URL: " + matcher.matches());
- }
-
- // 使用常量存储常用的正则表达式
- class RegexPatterns {
- public static final String EMAIL = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
- public static final String US_PHONE = "^(\\+1\\s?)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$";
- public static final String URL = "^(https?|ftp)://[^\\s/$.?#].[^\\s]*$";
- }
-
- Pattern emailPattern = Pattern.compile(RegexPatterns.EMAIL);
- System.out.println("\n使用常量存储的正则表达式:");
- System.out.println("test@example.com 是有效的邮箱: " + emailPattern.matcher("test@example.com").matches());
- }
- }
复制代码
测试正则表达式
- // 示例:测试正则表达式
- import java.util.regex.*;
- import java.util.*;
- public class TestingRegex {
- public static void main(String[] args) {
- // 创建测试用例
- List<RegexTestCase> testCases = new ArrayList<>();
-
- // 邮箱验证测试用例
- testCases.add(new RegexTestCase(
- "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$",
- Arrays.asList("user@example.com", "user.name@example.com", "user+name@example.com"),
- Arrays.asList("invalid.email@com", "@example.com", "user@.com")
- ));
-
- // 电话号码验证测试用例
- testCases.add(new RegexTestCase(
- "^(\\+1\\s?)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$",
- Arrays.asList("1234567890", "123-456-7890", "(123) 456-7890", "+1 123 456 7890"),
- Arrays.asList("123", "12345678901234567890", "abc-def-ghij")
- ));
-
- // 运行测试
- for (RegexTestCase testCase : testCases) {
- System.out.println("测试正则表达式: " + testCase.regex);
- Pattern pattern = Pattern.compile(testCase.regex);
-
- System.out.println("有效测试用例:");
- for (String validCase : testCase.validCases) {
- boolean result = pattern.matcher(validCase).matches();
- System.out.println(" " + validCase + " -> " + (result ? "通过" : "失败"));
- }
-
- System.out.println("无效测试用例:");
- for (String invalidCase : testCase.invalidCases) {
- boolean result = pattern.matcher(invalidCase).matches();
- System.out.println(" " + invalidCase + " -> " + (result ? "失败" : "通过"));
- }
-
- System.out.println();
- }
- }
-
- // 测试用例类
- static class RegexTestCase {
- String regex;
- List<String> validCases;
- List<String> invalidCases;
-
- RegexTestCase(String regex, List<String> validCases, List<String> invalidCases) {
- this.regex = regex;
- this.validCases = validCases;
- this.invalidCases = invalidCases;
- }
- }
- }
复制代码
性能考虑
总结
正则表达式是Java开发者必备的技能之一,它提供了强大的文本处理能力。本文从基础语法开始,逐步介绍了正则表达式的各种高级应用,包括:
1. 基础语法:字符类、量词、边界匹配和分组捕获是构建正则表达式的基础。
2. Java API:Pattern和Matcher类是Java中处理正则表达式的核心,掌握它们的使用方法是关键。
3. 实用技巧:通过邮箱验证、电话号码验证、URL解析和HTML标签处理等实际例子,展示了正则表达式的实际应用。
4. 高级应用:贪婪与懒惰匹配、回溯控制、零宽断言和性能优化等高级技巧可以帮助开发者解决更复杂的问题。
5. 最佳实践:提高正则表达式的可读性和维护性,进行充分的测试,并考虑性能因素,是编写高质量正则表达式的关键。
通过掌握这些技巧,Java开发者可以大大提升文本处理能力,更高效地解决各种文本匹配和处理问题。正则表达式虽然强大,但也需要谨慎使用,避免过度复杂的表达式,以免影响代码的可读性和性能。希望本文能够帮助Java开发者全面掌握正则表达式,并在实际开发中灵活应用。 |
|