Regex 工具 |
grep |
语言和函数库 |
Boost |
Delphi |
GNU (Linux) |
Groovy |
Java |
JavaScript |
.NET |
PCRE (C/C++) |
PCRE2 (C/C++) |
Perl |
PHP |
POSIX |
PowerShell |
Python |
R |
Ruby |
std::regex |
Tcl |
VBScript |
Visual Basic 6 |
wxWidgets |
XML Schema |
Xojo |
XQuery 和 XPath |
XRegExp |
数据库 |
MySQL |
Oracle |
PostgreSQL |
更多内容 |
简介 |
正则表达式快速入门 |
正则表达式教程 |
替换字符串教程 |
应用程序和语言 |
正则表达式范例 |
正则表达式参考 |
替换字符串参考 |
在 Java 中使用正则表达式
Java 4 (JDK 1.4) 及更新版本通过标准 java.util.regex
套件,全面支持正则表达式。由于 Java 长期以来缺乏正则表达式套件,因此也有许多第 3 方正则表达式套件可供 Java 使用。我将只讨论现在是 JDK 一部分的 Sun 正则表达式函数库。它的品质极佳,优于大多数第 3 方套件。除非您需要支持 JDK 的旧版本,否则 java.util.regex
套件是您的最佳选择。
Java 5 修复了一些错误,并添加支持 Unicode 区块。Java 6 修复了更多错误,但未添加任何功能。Java 7 添加 命名截取 和 Unicode 脚本。Java 13 允许在 回溯 中使用无限量词。
String 类别的快速正则表达式方法
Java String 类别有几个方法,让您可以在最少的代码中使用正则表达式对该字符串运行作业。缺点是您无法指定选项,例如「不区分大小写」或「点号符合换行符号」。基于性能考量,如果您会经常使用相同的正则表达式,也不应使用这些方法。
myString.matches("regex")
会根据字符串是否能完全符合正则表达式而传回 true 或 false。请务必记住,只有当整个字符串都能符合时,String.matches() 才会传回 true。换句话说:「regex」的应用方式就像你写了「^regex$」,并加上 字符串开头和结尾锚点。这与大多数其他正则表达式函数库不同,在那些函数库中,「快速比对测试」方法会在字符串中任何位置都能比对到正则表达式时传回 true。如果 myString 是 abc
,则 myString.matches("bc")
会传回 false。 bc
会比对到 abc
,但 ^bc$
(实际上是在这里使用)则不会。
myString.replaceAll("regex", "replacement")
会将字符串中所有符合正则表达式的比对结果替换为你指定的替换字符串。这没有什么意外。字符串中所有符合正则表达式的部分都会被替换。你可以通过 $1、$2、$3 等方式在替换文本中使用 截取括号 的内容。$0(零美元)会插入整个正则表达式比对结果。如果存在第 12 个反向引用,$12 会被替换为第 12 个反向引用;如果反向引用少于 12 个,则会被替换为第 1 个反向引用后接字面值「2」。如果反向引用有 12 个或更多,则无法在替换文本中插入第 1 个反向引用后紧接字面值「2」。
在替换文本中,如果美元符号后面没有数字,会掷出 IllegalArgumentException。如果反向引用少于 9 个,则美元符号后接大于反向引用数目的数字会掷出 IndexOutOfBoundsException。因此,如果替换字符串是由用户指定的字符串,请务必小心。若要插入美元符号作为字面值文本,请在替换文本中使用 \$
。当在原代码中将替换文本编码为字面值字符串时,请记住反斜线本身也必须加上转义字符:"\\$"
。
myString.split("regex")
会在每个正则表达式比对结果处拆分字符串。此方法会传回一个字符串数组,其中每个元素都是两个正则表达式比对结果之间的原始字符串的一部分。比对结果本身不会包含在数组中。使用 myString.split("regex", n)
来取得一个包含最多 n 个项目的数组。结果是字符串最多会被拆分 n-1 次。字符串中的最后一个项目是原始字符串未拆分的剩余部分。
使用 Pattern 类别
在 Java 中,您可以使用 Pattern.compile()
类别工厂编译正则表达式。此工厂会传回 Pattern
类型的对象。例如:Pattern myPattern = Pattern.compile("regex");
您可以指定某些选项作为第二个参数(选用)。Pattern.compile("regex", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE)
会让正则表达式对美国 ASCII 字符不分大小写,让 点 与换行符号相符,并让 字符串开头和结尾锚定 也与内嵌换行符号相符。当使用 Unicode 字符串时,如果您想让正则表达式对所有语言的所有字符不分大小写,请指定 Pattern.UNICODE_CASE
。除非您确定字符串只包含美国 ASCII 字符,而且您想提升性能,否则您应该总是指定 Pattern.CANON_EQ
来忽略 Unicode 编码的差异。
如果您会在原代码中频繁使用相同的正则表达式,您应该创建一个 Pattern
对象来提升性能。创建 Pattern
对象也让您可以将相符选项作为第二个参数传递给 Pattern.compile()
类别工厂。如果您使用上述其中一个 String
方法,指定选项的唯一方法是将模式修改器内嵌到正则表达式中。在正则表达式的开头加上 会让它不分大小写。
等于
Pattern.MULTILINE
, 等于
Pattern.DOTALL
,而 u
与 Pattern.UNICODE_CASE
相同。很不幸地,Pattern.CANON_EQ
没有等效的内嵌模式修改器。
使用 myPattern.split("subject")
来使用已编译的正则表达式分割主旨字符串。此调用的结果与 myString.split("regex")
完全相同。不同的是,前者较快,因为正则表达式已经编译过。
使用 Matcher 类别
除了分割字符串(请参阅前一段落)之外,您需要从 Pattern
对象创建一个 Matcher
对象。Matcher
会运行实际的工作。拥有两个独立类别的优点是,您可以从单一 Pattern
对象创建多个 Matcher
对象,并因此同时将正则表达式套用至多个主旨字符串。
若要创建 Matcher
对象,只需调用 Pattern.matcher()
,如下所示:myMatcher = Pattern.matcher("subject")
。如果您已经从相同的模式创建一个 Matcher
对象,请调用 myMatcher.reset("newsubject")
,而不是创建一个新的比对器对象,以减少垃圾和提升性能。无论如何,myMatcher
现在都已准备好运行任务。
要找出主旨字符串中正则表达式的第一个比对,请调用 myMatcher.find()
。要找出下一个比对,请再次调用 myMatcher.find()
。当 myMatcher.find()
传回 false,表示没有进一步的比对时,下一次调用 myMatcher.find()
将会再次找出第一个比对。Matcher
会在 find()
失败时自动重设为字符串的开头。
Matcher
对象会保留上次比对的结果。调用其方法 start()
、end()
和 group()
以取得关于整个正则表达式比对和 截取括号 之间的比对的详细数据。这些方法各接受一个整数参数,表示 反向引用 的数字。省略参数以取得关于整个正则表达式比对的信息。start()
是比对中第一个字符的索引。end()
是比对后第一个字符的索引。两者都相对于主旨字符串的开头。因此比对的长度为 end() - start()
group()
传回由正则表达式或一对截取括号比对的字符串。
myMatcher.replaceAll("replacement")
与 myString.replaceAll("regex", "replacement")
有完全相同的结果。再次强调,差别在于速度。
Matcher
类别让您可以在自己的代码中运行搜索和取代,并计算每个正则表达式比对的取代文本。您可以使用 appendReplacement()
和 appendTail()
来运行此操作。方法如下
StringBuffer myStringBuffer = new StringBuffer(); myMatcher = myPattern.matcher("subject"); while (myMatcher.find()) { if (checkIfThisMatchShouldBeReplaced()) { myMatcher.appendReplacement(myStringBuffer, computeReplacementString()); } } myMatcher.appendTail(myStringBuffer);
显然地,checkIfThisMatchShouldBeReplaced()
和 computeReplacementString()
是您提供的 placeholder 方法。第一个传回 true 或 false,表示是否应该进行任何取代。请注意,略过取代比使用与比对完全相同的文本取代比对要快得多。computeReplacementString()
传回实际的取代字符串。
正则表达式、字面字符串和反斜线
在 Java 字面字符串中,反斜线是转义字符。字面字符串 "\\"
是单一反斜线。在正则表达式中,反斜线也是转义字符。正则表达式 \\
比对单一反斜线。此正则表达式作为 Java 字符串时,会变成 "\\\\"
。没错:4 个反斜线比对一个反斜线。
正则表达式 \w
比对一个字符字符。作为 Java 字符串时,这会写成 "\\w"
。
当在 Java 代码中提供字面 Java 字符串作为 String.replaceAll() 等方法的取代字符串时,也会发生相同的反斜线混乱。在取代文本中,当您要使用实际的美元符号或反斜线取代正则表达式比对时,美元符号必须编码为 \$,反斜线必须编码为 \\。不过,反斜线也必须在字面 Java 字符串中转义。因此,当写成字面 Java 字符串时,取代文本中的单一美元符号会变成 "\\$"
。单一反斜线会变成 "\\\\"
。没错:4 个反斜线插入一个反斜线。