Java中正则匹配需使用Pattern和Matcher类,先通过Pattern.compile()编译正则表达式,再用Matcher进行匹配操作。

在Java里使用正则表达式匹配字符串,核心在于运用
java.util.regex
Pattern
Matcher
Pattern
Matcher
说起Java里的正则表达式,我首先想到的就是
Pattern.compile()
Matcher
具体怎么用呢?
你得先定义你的正则表达式字符串。比如,你想找字符串里的数字:
"\d+"
\
立即学习“Java免费学习笔记(深入)”;
接着,用
Pattern.compile()
Pattern
String regex = "\d+"; // 匹配一个或多个数字 Pattern pattern = Pattern.compile(regex);
然后,你需要一个
Matcher
Pattern
String text = "我有123个苹果和45个香蕉。"; Matcher matcher = pattern.matcher(text);
现在,有了
Matcher
Matcher
matches()
true
find()
group()
find()
group()
一个简单的例子,看看
find()
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo {
public static void main(String[] args) {
String text = "我有123个苹果和45个香蕉。";
String regex = "\d+"; // 匹配一个或多个数字
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
System.out.println("在文本中查找数字:");
while (matcher.find()) {
System.out.println("找到匹配: " + matcher.group() +
" (起始位置: " + matcher.start() +
", 结束位置: " + matcher.end() + ")");
}
// 另一个例子:使用matches()
String fullMatchText = "12345";
String partialMatchText = "abc123def";
Pattern digitPattern = Pattern.compile("\d+");
System.out.println("
使用matches()方法:");
System.out.println("'" + fullMatchText + "' 匹配 '\d+'? " + digitPattern.matcher(fullMatchText).matches()); // true
System.out.println("'" + partialMatchText + "' 匹配 '\d+'? " + digitPattern.matcher(partialMatchText).matches()); // false (因为整个字符串不全是数字)
}
}可以看到,
find()
matches()
在Java里玩转正则,首先得明白
Pattern
Matcher
Pattern
Pattern
Matcher
而
Matcher
Pattern.matcher(CharSequence input)
Matcher
除了前面提到的
matches()
find()
Matcher
lookingAt()
matches()
lookingAt()
true
group(int group)
()
group(int)
group(0)
group()
groupCount()
start()
end()
举个例子,从一段文本中提取日期:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DateExtractor {
public static void main(String[] args) {
String logEntry = "INFO: User logged in on 2023-10-26 at 10:30:00. Another event on 2024-01-15.";
// 匹配 YYYY-MM-DD 格式的日期,并捕获年、月、日
String dateRegex = "(\d{4})-(\d{2})-(\d{2})";
Pattern pattern = Pattern.compile(dateRegex);
Matcher matcher = pattern.matcher(logEntry);
while (matcher.find()) {
System.out.println("找到日期: " + matcher.group(0)); // 整个匹配
System.out.println(" 年份: " + matcher.group(1));
System.out.println(" 月份: " + matcher.group(2));
System.out.println(" 日期: " + matcher.group(3));
System.out.println(" 匹配起始位置: " + matcher.start());
System.out.println(" 匹配结束位置: " + matcher.end());
System.out.println("--------------------");
}
// lookingAt() 示例
String sentence = "Hello World!";
Pattern helloPattern = Pattern.compile("Hello");
System.out.println("
使用lookingAt(): " + helloPattern.matcher(sentence).lookingAt()); // true
Pattern worldPattern = Pattern.compile("World");
System.out.println("使用lookingAt(): " + worldPattern.matcher(sentence).lookingAt()); // false (因为World不在开头)
}
}通过捕获组,我们能更精细地从匹配结果中提取出想要的数据片段,这在数据解析和处理中非常常见。
正则虽然强大,但用不好也容易变成性能瓶颈。我个人在实践中总结了一些经验,希望能帮你避开一些坑。
性能优化策略:
预编译Pattern
Pattern.compile()
Pattern
// 推荐做法:预编译
private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$");
public boolean isValidEmail(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}
// 不推荐做法:每次都编译
public boolean isValidEmailBad(String email) {
return Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$").matcher(email).matches();
}后者在大量调用时会造成显著的性能下降。
避免“灾难性回溯”(Catastrophic Backtracking): 这是正则性能杀手。当一个正则表达式中包含嵌套的重复组,并且这些组可以匹配空字符串或者重叠匹配时,就可能发生。比如
"(a+)+"b
"aaaaaaaaaaaaaaaaaaaaaaaaac"
b
?>
// 避免灾难性回溯的例子 // 比如匹配HTML标签,简单写成 <.*> 可能遇到问题 // <a href="http://example.com">Link</a> 这种没问题 // 但如果是 <a href="http://example.com" title="some <tag> content">Link</a> 就会有问题 // 贪婪匹配 .* 会一直匹配到最后一个 > // 更好的做法是使用非贪婪匹配或排除特定字符 String badRegex = "<.*>"; // 贪婪匹配,可能导致回溯问题 String betterRegex = "<[^>]+>"; // 匹配 < 后跟一个或多个非 > 字符,再跟 > String nonGreedyRegex = "<.*?>"; // 非贪婪匹配
通常,用
[^...]
.*
使用Matcher.reset()
Matcher
Pattern
Matcher
Pattern p = Pattern.compile("\d+");
Matcher m = p.matcher(""); // 初始化一个空的Matcher
String[] texts = {"abc123def", "xyz456uvw"};
for (String text : texts) {
m.reset(text); // 重置Matcher的输入字符串
while (m.find()) {
System.out.println("找到: " + m.group());
}
}这比每次循环都创建一个新的
Matcher
常见陷阱:
Java字符串中的反斜杠转义: 前面提过了,
"\\"
.
"\."
(
"\("matches()
find()
matches()
find()
贪婪(Greedy)与非贪婪(Reluctant)模式: 默认情况下,量词(
*
+
?
{n,m}?
*?
+?
String html = "<div><span>Hello</span><span>World</span></div>";
Pattern greedyPattern = Pattern.compile("<span>.*</span>");
Matcher greedyMatcher = greedyPattern.matcher(html);
if (greedyMatcher.find()) {
System.out.println("贪婪匹配: " + greedyMatcher.group()); // 匹配到整个 "<span>Hello</span><span>World</span>"
}
Pattern reluctantPattern = Pattern.compile("<span>.*?</span>");
Matcher reluctantMatcher = reluctantPattern.matcher(html);
while (reluctantMatcher.find()) {
System.out.println("非贪婪匹配: " + reluctantMatcher.group()); // 分别匹配 "<span>Hello</span>" 和 "<span>World</span>"
}理解这个差异对正确提取数据至关重要。
正则表达式在数据清洗、日志分析、文本解析等领域简直是利器。它能帮你快速地从一堆混乱的数据中抓取出你想要的信息,或者替换掉不规范的内容。
数据提取:
最常见的莫过于从日志、HTML/XML片段、或者其他非结构化文本中提取特定数据。结合
find()
group()
例如,从一个多行文本中提取所有URL:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.List;
public class URLExtractor {
public static void main(String[] args) {
String multiLineText = """
Visit our website at https://www.example.com for more info.
You can also check out our blog: http://blog.example.org/latest.
Or our old site: ftp://old.example.net/files.txt
""";
// 一个相对通用的URL匹配模式
String urlRegex = "(https?|ftp)://[^\s/$.?#].[^\s]*";
Pattern pattern = Pattern.compile(urlRegex);
Matcher matcher = pattern.matcher(multiLineText);
List<String> urls = new ArrayList<>();
while (matcher.find()) {
urls.add(matcher.group());
}
System.out.println("提取到的URLs:");
urls.forEach(System.out::println);
}
}这个URL正则只是一个简化版,实际应用中可能需要更复杂的模式来覆盖各种URL格式。
数据替换:
Matcher
replaceAll()
replaceFirst()
例如,把文本中的所有手机号码替换成星号:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PhoneMasker {
public static void main(String[] args) {
String originalText = "联系我:13812345678 或 13987654321,座机010-88889999。";
// 匹配中国大陆手机号码(简化版)
String phoneRegex = "(1[3-9]\d{9})";
Pattern pattern = Pattern.compile(phoneRegex);
Matcher matcher = pattern.matcher(originalText);
// 将匹配到的手机号替换为星号
String maskedText = matcher.replaceAll("***********");
System.out.println("替换后的文本:
" + maskedText);
// 另一个例子:替换第一个匹配
String textWithEmails = "My email is user@example.com, and my secondary is test@domain.org.";
Pattern emailPattern = Pattern.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}");
Matcher emailMatcher = emailPattern.matcher(textWithEmails);
String firstEmailMasked = emailMatcher.replaceFirst("[MASKED_EMAIL]");
System.out.println("替换第一个邮件后的文本:
" + firstEmailMasked);
}
}字符串分割:
Pattern
split()
import java.util.regex.Pattern;
public class RegexSplitter {
public static void main(String[] args) {
String data = "apple, banana; orange grape";
// 以逗号、分号或制表符作为分隔符
Pattern pattern = Pattern.compile("[,;\t]");
String[] parts = pattern.split(data);
System.out.println("分割后的部分:");
for (String part : parts) {
System.out.println("- " + part.trim()); // trim() 去除可能存在的空格
}
// 限制分割次数
String limitedSplitData = "one:two:three:four";
Pattern colonPattern = Pattern.compile(":");
String[] limitedParts = colonPattern.split(limitedSplitData, 3); // 最多分割成3部分
System.out.println("
限制分割次数后的部分:");
for (String part : limitedParts) {
System.out.println("- " + part);
}
}
}String
split(String regex)
Pattern.compile(regex).split(this)
String.split()
Pattern.split()
总的来说,Java的正则表达式库功能强大且灵活,掌握它能让你在处理文本数据时事半功倍。不过,也要记住,正则不是万能药,对于非常复杂的解析任务,可能需要配合其他解析器(如XML解析器、JSON库)一起使用。关键在于理解其核心机制,并根据具体需求选择最合适的工具。
以上就是java如何使用正则表达式匹配字符串 java正则应用的实用技巧教程的详细内容,更多请关注php中文网其它相关文章!
java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号