Java 正则表达式教程展示了如何使用正则表达式解析 Java 中的文本。
正则表达式
正则表达式用于文本搜索和更高级的文本操作。 正则表达式内置在包括 grep 和 sed 的工具,包括 vi 和 emacs 的文本编辑器,包括 Perl,Java 和 C# 的编程语言中。
Java 具有用于处理正则表达式的内置 API。 它位于java.util.regex
中。
正则表达式定义字符串的搜索模式。 Pattern
是正则表达式的编译表示。 Matcher
是一种引擎,可解释模式并针对输入字符串执行匹配操作。 匹配器具有诸如find()
,matches()
和end()
之类的方法来执行匹配操作。 如果存在解析正则表达式的异常,则 Java 会抛出PatternSyntaxException
。
正则表达式示例
下表显示了几个正则表达式字符串。
正则表达式 | 含义 |
---|---|
. |
匹配任何单个字符。 |
? |
一次匹配或根本不匹配前面的元素。 |
+ |
与前面的元素匹配一次或多次。 |
* |
与前面的元素匹配零次或多次。 |
^ |
匹配字符串中的起始位置。 |
$ |
匹配字符串中的结束位置。 |
| |
备用运算符。 |
[abc] |
匹配 a 或 b 或 c。 |
[a-c] |
范围; 匹配 a 或 b 或 c。 |
[^abc] |
否定,匹配除 a 或 b 或 c 之外的所有内容。 |
\s |
匹配空白字符。 |
\w |
匹配单词字符; 等同于[a-zA-Z_0-9] |
Java 简单正则表达式
在第一个示例中,我们将单词匹配单词列表。
JavaRegexEx.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
正则表达式匹配。
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);
}
}
我们浏览一下单词表。 使用matcher()
方法创建一个匹配器。 如果单词与正则表达式匹配,则matches()
方法返回 true。
Seven matches
even does not match
Maven does not match
Amen does not match
eleven does not match
这是输出。
Java Regex 锚点
锚点匹配给定文本内字符的位置。 在下一个示例中,我们查看字符串是否位于句子的开头。
JavaRegexAnchor.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
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 个名字。
Pattern p = Pattern.compile("Jane|Beky|Robert");
此正则表达式查找“ Jane”,“ Beky”或“ Robert”字符串。
Java Regex 捕获组
捕获组技术是一种将多个字符视为一个单元的方法。 通过将字符放置在一组圆括号内来创建它们。 例如,(book)是包含’b’,’o’,’o’,’k’,字符的单个组。
捕获组技术使我们能够找出字符串中与常规模式匹配的那些部分。 Mather 的group()
方法返回在先前的匹配操作期间给定组捕获的输入子序列。
JavaRegexGroups.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 标签。
<p>
<code>
</code>
</p>
This is the output.
Java Regex 替换字符串
可以用replaceAll()
和replaceFirst()
方法替换字符串。 该方法返回修改后的字符串。
JavaRegexReplacingStrings.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 标签。
Pattern p = Pattern.compile("<[^>]*>");
此模式定义与 HTML 标签匹配的正则表达式。
String stripped = matcher.replaceAll("");
我们使用replaceAll()
方法删除所有标签。
Java Regex 分割文本
可以使用Pattern's
split()
方法分割文本。
data.csv
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
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 文件读取值并计算它们的总和。 它使用正则表达式读取数据。
List<String> lines = Files.readAllLines(myPath);
一次拍摄,我们用Files.readAllLines()
将所有数据读入字符串列表。
String regex = ",";
正则表达式是逗号字符。
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
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);
}
});
}
}
该示例对正则表达式执行不区分大小写的匹配。
Pattern p = Pattern.compile("dog", Pattern.CASE_INSENSITIVE);
通过将Pattern.CASE_INSENSITIVE
作为第二个参数设置为Pattern.compile()
来设置不区分大小写的匹配。
Java Regex 子模式
子模式是模式中的模式。 子模式使用()
字符创建。
JavaRegexSubpatterns.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);
}
}
}
}
该示例创建一个子模式。
Pattern p = Pattern.compile("book(worm|mark|keeper)?");
正则表达式使用子模式。 它与书呆子,书签,簿记员和书本单词匹配。
Java Regex 电子邮件示例
在以下示例中,我们创建一个用于检查电子邮件地址的正则表达式模式。
JavaRegexEmail.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);
}
}
}
}
本示例仅提供一种可能的解决方案。
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,信息,旅行,清洁,旅行保险。 最大长度可以为 63 个字符,但是今天大多数域都少于 18 个字符。 还有一个点字符。 这是因为某些顶级域包含两个部分: 例如 co.uk。