原文:http://zetcode.com/java/regex/

Java 正则表达式教程展示了如何使用正则表达式解析 Java 中的文本。

正则表达式

正则表达式用于文本搜索和更高级的文本操作。 正则表达式内置在包括grepsed的工具,包括 vi 和 emacs 的文本编辑器,包括 Perl,Java 和 C# 的编程语言中。

Java 具有用于处理正则表达式的内置 API。 它位于java.util.regex中。

正则表达式定义字符串的搜索模式。 Pattern是正则表达式的编译表示。 Matcher是一种引擎,可解释模式并针对输入字符串执行匹配操作。 匹配器具有诸如find()matches()end()之类的方法来执行匹配操作。 如果存在解析正则表达式的异常,则 Java 会抛出PatternSyntaxException

正则表达式示例

下表显示了几个正则表达式字符串。

正则表达式 含义
. 匹配任何单个字符。
? 一次匹配或根本不匹配前面的元素。
+ 与前面的元素匹配一次或多次。
* 与前面的元素匹配零次或多次。
^ 匹配字符串中的起始位置。
$ 匹配字符串中的结束位置。
` ` 备用运算符。
[abc] 匹配abc
[a-c] 范围; 匹配abc
[^abc] 否定,匹配除abc之外的所有内容。
\s 匹配空白字符。
\w 匹配单词字符; 等同于[a-zA-Z_0-9]

Java 简单正则表达式

在第一个示例中,我们将单词匹配单词列表。

JavaRegexEx.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.regex.Matcher;
  5. import java.util.regex.Pattern;
  6. public class JavaRegexEx {
  7. public static void main(String[] args) {
  8. List<String> words = Arrays.asList("Seven", "even",
  9. "Maven", "Amen", "eleven");
  10. Pattern p = Pattern.compile(".even");
  11. for (String word: words) {
  12. Matcher m = p.matcher(word);
  13. if (m.matches()) {
  14. System.out.printf("%s matches%n", word);
  15. } else {
  16. System.out.printf("%s does not match%n", word);
  17. }
  18. }
  19. }
  20. }

在示例中,列表中有五个单词。 我们检查哪些单词与.even正则表达式匹配。

  1. Pattern p = Pattern.compile(".even");

我们编译模式。 点(。)元字符代表文本中的任何单个字符。

  1. for (String word: words) {
  2. Matcher m = p.matcher(word);
  3. if (m.matches()) {
  4. System.out.printf("%s matches%n", word);
  5. } else {
  6. System.out.printf("%s does not match%n", word);
  7. }
  8. }

我们浏览一下单词表。 使用matcher()方法创建一个匹配器。 如果单词与正则表达式匹配,则matches()方法返回true

  1. Seven matches
  2. even does not match
  3. Maven does not match
  4. Amen does not match
  5. eleven does not match

这是输出。

Java Regex 锚点

锚点匹配给定文本内字符的位置。 在下一个示例中,我们查看字符串是否位于句子的开头。

JavaRegexAnchor.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.regex.Matcher;
  5. import java.util.regex.Pattern;
  6. public class JavaRegexAnchor {
  7. public static void main(String[] args) {
  8. List<String> sentences = Arrays.asList("I am looking for Jane.",
  9. "Jane was walking along the river.",
  10. "Kate and Jane are close friends.");
  11. Pattern p = Pattern.compile("^Jane");
  12. for (String word : sentences) {
  13. Matcher m = p.matcher(word);
  14. if (m.find()) {
  15. System.out.printf("%s matches%n", word);
  16. } else {
  17. System.out.printf("%s does not match%n", word);
  18. }
  19. }
  20. }
  21. }

我们有三个句子。 搜索模式为^Jane。 该模式检查"Jane"字符串是否位于文本的开头。 Jane\.$会在句子结尾处查找"Jane"

Java Regex 交替

交替运算符| 可以创建具有多种选择的正则表达式。

JavaRegexAlternation.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.regex.Matcher;
  5. import java.util.regex.Pattern;
  6. public class JavaRegexAlternation {
  7. public static void main(String[] args) {
  8. List<String> users = Arrays.asList("Jane", "Thomas", "Robert",
  9. "Lucy", "Beky", "John", "Peter", "Andy");
  10. Pattern p = Pattern.compile("Jane|Beky|Robert");
  11. for (String user : users) {
  12. Matcher m = p.matcher(user);
  13. if (m.matches()) {
  14. System.out.printf("%s matches%n", user);
  15. } else {
  16. System.out.printf("%s does not match%n", user);
  17. }
  18. }
  19. }
  20. }

列表中有 9 个名字。

  1. Pattern p = Pattern.compile("Jane|Beky|Robert");

此正则表达式查找"Jane""Beky""Robert"字符串。

Java Regex 捕获组

捕获组技术是一种将多个字符视为一个单元的方法。 通过将字符放置在一组圆括号内来创建它们。 例如,(book)是包含'b', 'o', 'o', 'k'字符的单个组。

捕获组技术使我们能够找出字符串中与常规模式匹配的那些部分。 Matchergroup()方法返回在先前的匹配操作期间给定组捕获的输入子序列。

JavaRegexGroups.java

  1. package com.zetcode;
  2. import java.util.regex.Matcher;
  3. import java.util.regex.Pattern;
  4. public class JavaRegexGroups {
  5. public static void main(String[] args) {
  6. String content = "<p>The <code>Pattern</code> is a compiled "
  7. + "representation of a regular expression.</p>";
  8. Pattern p = Pattern.compile("(</?[a-z]*>)");
  9. Matcher matcher = p.matcher(content);
  10. while (matcher.find()) {
  11. System.out.println(matcher.group(1));
  12. }
  13. }
  14. }

本示例通过捕获一组字符来打印提供的字符串中的所有 HTML 标签。

  1. <p>
  2. <code>
  3. </code>
  4. </p>

这是输出。

Java Regex 替换字符串

可以用replaceAll()replaceFirst()方法替换字符串。 该方法返回修改后的字符串。

JavaRegexReplacingStrings.java

  1. package com.zetcode;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.net.MalformedURLException;
  6. import java.net.URL;
  7. import java.nio.charset.StandardCharsets;
  8. import java.util.regex.Matcher;
  9. import java.util.regex.Pattern;
  10. import java.util.stream.Collectors;
  11. public class JavaRegexReplacingStrings {
  12. public static void main(String[] args) throws MalformedURLException, IOException {
  13. URL url = new URL("http://www.something.com");
  14. try (InputStreamReader isr = new InputStreamReader(url.openStream(),
  15. StandardCharsets.UTF_8);
  16. BufferedReader br = new BufferedReader(isr)) {
  17. String content = br.lines().collect(
  18. Collectors.joining(System.lineSeparator()));
  19. Pattern p = Pattern.compile("<[^>]*>");
  20. Matcher matcher = p.matcher(content);
  21. String stripped = matcher.replaceAll("");
  22. System.out.println(stripped);
  23. }
  24. }
  25. }

该示例读取网页的 HTML 数据,并使用正则表达式剥离其 HTML 标签。

  1. Pattern p = Pattern.compile("<[^>]*>");

此模式定义与 HTML 标签匹配的正则表达式。

  1. String stripped = matcher.replaceAll("");

我们使用replaceAll()方法删除所有标签。

Java Regex 分割文本

可以使用Patternsplit()方法分割文本。

data.csv

  1. 22, 1, 3, 4, 5, 17, 18
  2. 2, 13, 4, 1, 8, 4
  3. 3, 21, 4, 5, 1, 48, 9, 42

我们从data.csv文件中读取。

JavaRegexSplitText.java

  1. package com.zetcode;
  2. import java.io.IOException;
  3. import java.nio.file.Files;
  4. import java.nio.file.Path;
  5. import java.nio.file.Paths;
  6. import java.util.List;
  7. import java.util.regex.Pattern;
  8. public class JavaRegexSplitText {
  9. static int sum = 0;
  10. public static void main(String[] args) throws IOException {
  11. Path myPath = Paths.get("src/main/resources/data.csv");
  12. List<String> lines = Files.readAllLines(myPath);
  13. String regex = ",";
  14. Pattern p = Pattern.compile(regex);
  15. lines.forEach((line) -> {
  16. String[] parts = p.split(line);
  17. for (String part : parts) {
  18. String val = part.trim();
  19. sum += Integer.valueOf(val);
  20. }
  21. });
  22. System.out.printf("Sum of values: %d", sum);
  23. }
  24. }

这些示例从 CSV 文件读取值并计算它们的总和。 它使用正则表达式读取数据。

  1. List<String> lines = Files.readAllLines(myPath);

一次拍摄,我们用Files.readAllLines()将所有数据读入字符串列表。

  1. String regex = ",";

正则表达式是逗号字符。

  1. lines.forEach((line) -> {
  2. String[] parts = p.split(line);
  3. for (String part : parts) {
  4. String val = part.trim();
  5. sum += Integer.valueOf(val);
  6. }
  7. });

我们遍历行,并使用split将它们拆分为字符串数组。 我们用trim()分隔空格并计算总和值。

Java 不区分大小写的正则表达式

通过设置Pattern.CASE_INSENSITIVE标志,我们可以实现不区分大小写的匹配。

JavaRegexCaseInsensitive.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.regex.Matcher;
  5. import java.util.regex.Pattern;
  6. public class JavaRegexCaseInsensitive {
  7. public static void main(String[] args) {
  8. List<String> users = Arrays.asList("dog", "Dog", "DOG", "Doggy");
  9. Pattern p = Pattern.compile("dog", Pattern.CASE_INSENSITIVE);
  10. users.forEach((user) -> {
  11. Matcher m = p.matcher(user);
  12. if (m.matches()) {
  13. System.out.printf("%s matches%n", user);
  14. } else {
  15. System.out.printf("%s does not match%n", user);
  16. }
  17. });
  18. }
  19. }

该示例对正则表达式执行不区分大小写的匹配。

  1. Pattern p = Pattern.compile("dog", Pattern.CASE_INSENSITIVE);

通过将Pattern.CASE_INSENSITIVE作为第二个参数设置为Pattern.compile()来设置不区分大小写的匹配。

Java Regex 子模式

子模式是模式中的模式。 子模式使用()字符创建。

JavaRegexSubpatterns.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.regex.Matcher;
  5. import java.util.regex.Pattern;
  6. public class JavaRegexSubpatterns {
  7. public static void main(String[] args) {
  8. List<String> words = Arrays.asList("book", "bookshelf", "bookworm",
  9. "bookcase", "bookish", "bookkeeper", "booklet", "bookmark");
  10. Pattern p = Pattern.compile("book(worm|mark|keeper)?");
  11. for (String word : words) {
  12. Matcher m = p.matcher(word);
  13. if (m.matches()) {
  14. System.out.printf("%s matches%n", word);
  15. } else {
  16. System.out.printf("%s does not match%n", word);
  17. }
  18. }
  19. }
  20. }

该示例创建一个子模式。

  1. Pattern p = Pattern.compile("book(worm|mark|keeper)?");

正则表达式使用子模式。 它与书呆子,书签,簿记员和书本单词匹配。

Java Regex 电子邮件示例

在以下示例中,我们创建一个用于检查电子邮件地址的正则表达式模式。

JavaRegexEmail.java

  1. package com.zetcode;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.regex.Matcher;
  5. import java.util.regex.Pattern;
  6. public class JavaRegexEmail {
  7. public static void main(String[] args) {
  8. List<String> emails = Arrays.asList("luke@gmail.com",
  9. "andy@yahoocom", "34234sdfa#2345", "f344@gmail.com");
  10. String regex = "^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\\.[a-zA-Z.]{2,18}$";
  11. Pattern p = Pattern.compile(regex);
  12. for (String email : emails) {
  13. Matcher m = p.matcher(email);
  14. if (m.matches()) {
  15. System.out.printf("%s matches%n", email);
  16. } else {
  17. System.out.printf("%s does not match%n", email);
  18. }
  19. }
  20. }
  21. }

本示例仅提供一种可能的解决方案。

  1. String regex = "^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\\.[a-zA-Z.]{2,18}$";

^和后$个字符提供精确的模式匹配。 模式前后不允许有字符。 电子邮件分为五个部分。 第一部分是本地部分。 这通常是公司,个人或昵称的名称。 [a-zA-Z0-9._-]+列出了所有可能的字符,我们可以在本地使用。 它们可以使用一次或多次。

第二部分由文字@字符组成。 第三部分是领域部分。 通常是电子邮件提供商的域名,例如 yahoo 或 gmail。 [a-zA-Z0-9-]+是一个字符集,提供了可在域名中使用的所有字符。 +量词使用这些字符中的一个或多个。

第四部分是点字符。 它前面有转义字符(\)。 这是因为点字符是一个元字符,并且具有特殊含义。 通过转义,我们得到一个文字点。

最后一部分是顶级域:[a-zA-Z.]{2,18}。 顶级域可以包含 2 到 18 个字符,例如sk, net, info, travel, cleaning, travelinsurance。 最大长度可以为 63 个字符,但是今天大多数域都少于 18 个字符。 还有一个点字符。 这是因为某些顶级域包含两个部分: 例如co.uk

在本教程中,我们使用了 Java 中的正则表达式。 您可能也对相关教程感兴趣: Java 教程用 Java 读取文本文件。