# Java 正则表达式教程

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

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

## 正则表达式

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

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

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

## 正则表达式示例

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

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

## Java 简单正则表达式

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

`JavaRegexEx.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexEx {

    public static void main(String[] args) {

        List<String> words = Arrays.asList("Seven", "even",
                "Maven", "Amen", "eleven");

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

        for (String word: words) {

            Matcher m = p.matcher(word);  

            if (m.matches()) {
                System.out.printf("%s matches%n", word);
            } else {
                System.out.printf("%s does not match%n", word);
            }
        }
    }
}

```

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

```java
Pattern p = Pattern.compile(".even");

```

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

```java
for (String word: words) {

    Matcher m = p.matcher(word);  

    if (m.matches()) {
        System.out.printf("%s matches%n", word);
    } else {
        System.out.printf("%s does not match%n", word);
    }
}

```

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

```java
Seven matches
even does not match
Maven does not match
Amen does not match
eleven does not match

```

这是输出。

## Java Regex 锚点

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

`JavaRegexAnchor.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexAnchor {

    public static void main(String[] args) {

        List<String> sentences = Arrays.asList("I am looking for Jane.",
                "Jane was walking along the river.",
                "Kate and Jane are close friends.");

        Pattern p = Pattern.compile("^Jane");

        for (String word : sentences) {

            Matcher m = p.matcher(word);

            if (m.find()) {
                System.out.printf("%s matches%n", word);
            } else {
                System.out.printf("%s does not match%n", word);
            }
        }
    }
}

```

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

## Java Regex 交替

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

`JavaRegexAlternation.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexAlternation {

    public static void main(String[] args) {

        List<String> users = Arrays.asList("Jane", "Thomas", "Robert",
                "Lucy", "Beky", "John", "Peter", "Andy");

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

        for (String user : users) {

            Matcher m = p.matcher(user);

            if (m.matches()) {
                System.out.printf("%s matches%n", user);
            } else {
                System.out.printf("%s does not match%n", user);
            }
        }
    }
}

```

列表中有 9 个名字。

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

```

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

## Java Regex 捕获组

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

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

`JavaRegexGroups.java`

```java
package com.zetcode;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexGroups {

    public static void main(String[] args) {

        String content = "<p>The <code>Pattern</code> is a compiled "
                + "representation of a regular expression.</p>";

        Pattern p = Pattern.compile("(</?[a-z]*>)");

        Matcher matcher = p.matcher(content);

        while (matcher.find()) {

            System.out.println(matcher.group(1));
        }
    }
}

```

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

```java
<p>
<code>
</code>
</p>

```

这是输出。

## Java Regex 替换字符串

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

`JavaRegexReplacingStrings.java`

```java
package com.zetcode;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class JavaRegexReplacingStrings {

    public static void main(String[] args) throws MalformedURLException, IOException {

        URL url = new URL("http://www.something.com");

        try (InputStreamReader isr = new InputStreamReader(url.openStream(),
                StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr)) {

            String content = br.lines().collect(
                Collectors.joining(System.lineSeparator()));

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

            Matcher matcher = p.matcher(content);
            String stripped = matcher.replaceAll("");

            System.out.println(stripped);
        }
    }
}

```

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

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

```

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

```java
String stripped = matcher.replaceAll("");

```

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

## Java Regex 分割文本

可以使用`Pattern`的`split()`方法分割文本。

`data.csv`

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

```

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

`JavaRegexSplitText.java`

```java
package com.zetcode;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.regex.Pattern;

public class JavaRegexSplitText {

    static int sum = 0;

    public static void main(String[] args) throws IOException {

        Path myPath = Paths.get("src/main/resources/data.csv");

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

        String regex = ",";

        Pattern p = Pattern.compile(regex);

        lines.forEach((line) -> {

            String[] parts = p.split(line);

            for (String part : parts) {

                String val = part.trim();

                sum += Integer.valueOf(val);
            }

        });

        System.out.printf("Sum of values: %d", sum);
    }
}

```

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

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

```

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

```java
String regex = ",";

```

正则表达式是逗号字符。

```java
lines.forEach((line) -> {

    String[] parts = p.split(line);

    for (String part : parts) {

        String val = part.trim();

        sum += Integer.valueOf(val);
    }

});

```

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

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

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

`JavaRegexCaseInsensitive.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexCaseInsensitive {

    public static void main(String[] args) {

        List<String> users = Arrays.asList("dog", "Dog", "DOG", "Doggy");

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

        users.forEach((user) -> {

            Matcher m = p.matcher(user);

            if (m.matches()) {
                System.out.printf("%s matches%n", user);
            } else {
                System.out.printf("%s does not match%n", user);
            }
        });
    }
}

```

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

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

```

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

## Java Regex 子模式

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

`JavaRegexSubpatterns.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexSubpatterns {

    public static void main(String[] args) {

        List<String> words = Arrays.asList("book", "bookshelf", "bookworm",
                "bookcase", "bookish", "bookkeeper", "booklet", "bookmark");

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

        for (String word : words) {

            Matcher m = p.matcher(word);

            if (m.matches()) {
                System.out.printf("%s matches%n", word);
            } else {
                System.out.printf("%s does not match%n", word);
            }
        }        
    }
}

```

该示例创建一个子模式。

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

```

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

## Java Regex 电子邮件示例

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

`JavaRegexEmail.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaRegexEmail {

    public static void main(String[] args) {

        List<String> emails = Arrays.asList("luke@gmail.com", 
                "andy@yahoocom", "34234sdfa#2345", "f344@gmail.com");

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

        Pattern p = Pattern.compile(regex);

        for (String email : emails) {

            Matcher m = p.matcher(email);

            if (m.matches()) {
                System.out.printf("%s matches%n", email);
            } else {
                System.out.printf("%s does not match%n", email);
            }
        }
    }
}

```

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

```java
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 教程](/lang/java/)或[用 Java](/articles/javareadtext/) 读取文本文件。