如果您需要复习正则表达式的使用方法,请先查看我们的 交互式教程!
Java 通过标准 Java 库中 java.util.regex
包中的类来支持正则表达式。虽然 Java 正则表达式库支持的一些高级功能与 PCRE 存在一些差异,但它们都共享大部分语法,并且表达式可以在 Java 和其他语言中使用。
在下面的示例中,如果您正在尝试代码,请确保在源文件顶部导入以下包
import java.util.regex.*;
在 Java 中,普通字符串可以包含特殊字符(也称为 转义序列),这些字符以反斜杠 (\
) 开头,并标识特殊文本片段,例如换行符 (\n
) 或制表符 (\t
)。因此,在 Java 代码中编写正则表达式时,需要转义每个元字符的反斜杠,以让编译器知道它不是错误的转义序列。
例如,取模式 "There are \d dogs"
。在 Java 中,您将通过使用转义序列 \\
(有效地用自身转义反斜杠)来转义数字元字符的反斜杠,从而创建模式 "There are \\d dogs"
。
这仅在将模式硬编码到 Java 代码中时才需要,因为从用户输入或文件中读取的字符串是逐个字符读取的,并且不会解释转义序列。这是一种常见的解决此问题的方法,方法是将模式放在 Properties
或资源文件中,以便更容易阅读和理解。
像 C# 或 Python 这样的其他语言支持原始字符串的概念,但 Java 尚未将此有用功能添加到核心语言中。
在 Java 中使用正则表达式通常涉及实例化一个 Pattern
,并将其与某些文本进行匹配。最简单的方法是调用静态方法 Pattern.matches()
,它接受一个输入字符串和要与其匹配的正则表达式,并简单地返回模式是否与字符串匹配。
boolean isMatch = Pattern.matches(String regex, String inputStr)
但是,这不会为您提供任何其他信息,例如模式在输入字符串中的匹配位置或匹配的组。因此,出于大多数目的,编译新的 Pattern
然后为要匹配的每个输入字符串使用它来创建新的 Matcher
既更有用也更高效,后者将保存匹配的结果。
Pattern ptrn = Pattern.compile(String regex)
Matcher matcher = ptrn.matcher(String inputStr)
// 让我们使用正则表达式来匹配日期字符串。 Pattern ptrn = Pattern.compile("([a-zA-Z]+) (\\d+)"); Matcher matcher = ptrn.matcher("June 24"); if (matcher.matches()) { // 的确,表达式 "([a-zA-Z]+) (\d+)" 匹配日期字符串 // 要获取匹配的索引,您可以读取 Matcher 对象的 // start 和 end 值。 // 这将打印 [0, 7],因为它从字符串的开头和结尾匹配 // 字符串 System.out.println("Match at index [" + matcher.start() + ", " + matcher.end() + ")"); // 要获取完全匹配的文本,您可以读取 Matcher 对象的 group // 这将打印 "June 24" System.out.println("Match: " + matcher.group()); }
在正则表达式中捕获组与上面示例中匹配字符串一样简单。使用 Pattern
匹配输入字符串后,您只需遍历返回的 Matcher
中提取的组即可。
// 让我们使用正则表达式从一些日期字符串中捕获数据。 String pattern = "([a-zA-Z]+) (\\d+)"; Pattern ptrn = Pattern.compile("([a-zA-Z]+) (\\d+)"); Matcher matcher = ptrn.matcher("June 24, August 9, Dec 12"); // 这将打印每个匹配项以及输入字符串中匹配项找到的索引 // 其中匹配项被找到: // June 24 at index [0, 7) // August 9 at index [9, 17) // Dec 12 at index [19, 25) while (matcher.find()) { System.out.println(String.format("Match: %s at index [%d, %d]", matcher.group(), matcher.start(), matcher.end())); } // 如果我们再次遍历匹配中的组,首先将 // matcher 重置为从输入字符串的开头开始。 matcher.reset(); // 对于每个匹配项,我们都可以通过读取 // 捕获的组来提取捕获的信息。 while (matcher.find()) { // 这将打印此匹配中捕获的组数 System.out.println(String.format("%d groups captured", matcher.groupCount())); // 这将打印每个匹配项的月份和日期。请记住, // 第一个组始终是整个匹配文本,因此月份从 // 索引 1 开始。 System.out.println("Month: " + matcher.group(1) + ", Day: " + matcher.group(2)); // 匹配中的每个组也有一个开始和结束索引,它是 // 输入字符串中找到组的索引。 System.out.println(String.format("Month found at[%d, %d)", matcher.start(1), matcher.end(1))); }
另一个常见任务是使用正则表达式查找和替换字符串的一部分,例如,替换旧电子邮件域的所有实例,或交换某些文本的顺序。您可以在 Java 中使用 Matcher.replaceAll()
和 Matcher.replaceFirst()
方法执行此操作。这两种方法首先将匹配器重置为从输入字符串的开头开始到字符串的末尾或第一个匹配项的末尾。
替换字符串可以包含对模式中捕获的组的引用(使用美元符号 $),也可以只包含常规文字字符串。
String replacedString = matcher.replaceAll(String inputStr)
String replacedString = matcher.replaceFirst(String inputStr)
// 让我们尝试反转一些日期字符串中日期和月份的顺序 // 字符串。请注意,替换字符串也包含元字符 // (对捕获组的反向引用),因此我们也对该字符串使用逐字 // 字符串。 Pattern ptrn = Pattern.compile("([a-zA-Z]+) (\\d+)"); Matcher matcher = ptrn.matcher("June 24, August 9, Dec 12"); // 这将内联重新排序字符串并打印: // 24 of June, 9 of August, 12 of Dec // 请记住,第一个组始终是完整的匹配文本,因此 // 月份和日期索引从 1 开始而不是从零开始。 String replacedString = matcher.replaceAll("$2 of $1"); System.out.println(replacedString);
Pattern
标志在编译Pattern
时,您会注意到可以传递额外的标志来更改输入字符串的匹配方式。大多数可用的标志都是为了方便,可以直接写入正则表达式本身,但有些在某些情况下可能很有用。
Pattern.CASE_INSENSITIVE
使模式不区分大小写,以便它匹配不同大小写形式的字符串Pattern.MULTILINE
,并允许起始和结束元字符(分别为^和$)匹配每一行的开头和结尾,而不是匹配整个输入字符串的开头和结尾Pattern.DOTALL
允许点元字符(.)也匹配换行符Pattern.LITERAL
使模式成为字面量,这意味着转义字符按原样匹配。例如,模式"\d"
将匹配反斜杠后跟'd'字符,而不是数字字符有关在 Java 中使用正则表达式的更多信息,请访问以下链接