正则表达式总结 java 等
这个经常用的到,就来总结一下
#一下是JAVA中的正则表达式
在 JDK1.4 里有了自己的正则表达式 API 包,JAVA 程序员可以免去找第三方提供的正则表达式库的周折了,我们现在就马上来了解一下这个 SUN 提供的迟来恩物 - - 对我来说确实如此。
java.util.regex
它包括两个类: Pattern和 Matcher
Pattern | 一个 Pattern 是一个正则表达式经编译后的表现模式。 |
---|---|
Matcher | 一个 Matcher 对象是一个状态机器,它依据 Pattern 对象做为匹配模式对字符串展开匹配检查。 |
首先一个 Pattern 实例订制了一个所用语法与 PERL 的类似的正则表达式经编译后的模式,然后一个 Matcher 实例在这个给定的 Pattern 实例的模式控制下进行字符串的匹配工作。
以下我们就分别来看看这两个类:
java.util.regex
类 Pattern
java.lang.Object
java.util.regex.Pattern
- 所有已实现的接口:
- Serializable
public final class Patternextends Objectimplements Serializable
正则表达式的编译表示形式。
指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建 Matcher
对象,依照正则表达式,该对象可以与任意字符序列
匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。
因此,典型的调用顺序是
Pattern p = Pattern.compile
("a*b"); Matcher m = p.matcher
("aaaaab"); boolean b = m.matches
();
在仅使用一次正则表达式时,可以方便地通过此类定义 matches
方法。此方法编译表达式并在单个调用中将输入序列与其匹配。语句
boolean b = Pattern.matches("a*b", "aaaaab");
等效于上面的三个语句,尽管对于重复的匹配而言它效率不高,因为它不允许重用已编译的模式。
此类的实例是不可变的,可供多个并发线程安全使用。
--现在我们先来看一个简单的例子,再通过分析它来了解怎样生成一个Pattern对象并且编译一个正则表达式,最后根据这个正则表达式将目标字符串进行分割:
import java.util.regex.*;
public class Replacement{
public static void main(String[] args) throws Exception {
// 生成一个Pattern,同时编译一个正则表达式
Pattern p = Pattern.compile("[/]+");
//用Pattern的split()方法把字符串按"/"分割
String[] result = p.split(
"Kevin has seen《LEON》seveal times,because it is a good film."
+"/ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部"
+"好电影。/名词:凯文。");
for (int i=0; i<result.length; i++)
System.out.println(result[i]);
}
}
输出结果为:
Kevin has seen《LEON》seveal times,because it is a good film.
凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。
名词:凯文。
Matcher
类的实例用于此目的则不安全。
正则表达式的构造摘要
的非捕获组
构造 | 匹配 |
---|---|
字符 | |
x | 字符 x |
\\ | 反斜线字符 |
\0n | 带有八进制值 0 的字符 n (0 <= n <= 7) |
\0nn | 带有八进制值 0 的字符 nn (0 <= n <= 7) |
\0mnn | 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7) |
\xhh | 带有十六进制值 0x 的字符 hh |
\uhhhh | 带有十六进制值 0x 的字符 hhhh |
\t | 制表符 ('\u0009') |
\n | 新行(换行)符 ('\u000A') |
\r | 回车符 ('\u000D') |
\f | 换页符 ('\u000C') |
\a | 报警 (bell) 符 ('\u0007') |
\e | 转义符 ('\u001B') |
\cx | 对应于 x 的控制符 |
字符类 | |
[abc] | a、b 或 c(简单类) |
[^abc] | 任何字符,除了 a、b 或 c(否定) |
[a-zA-Z] | a 到 z 或 A 到 Z,两头的字母包括在内(范围) |
[a-d[m-p]] | a 到 d 或 m 到 p:[a-dm-p](并集) |
[a-z&&[def]] | d、e 或 f(交集) |
[a-z&&[^bc]] | a 到 z,除了 b 和 c:[ad-z](减去) |
[a-z&&[^m-p]] | a 到 z,而非 m 到 p:[a-lq-z](减去) |
预定义字符类 | |
. | 任何字符(与行结束符可能匹配也可能不匹配) |
\d | 数字:[0-9] |
\D | 非数字: [^0-9] |
\s | 空白字符:[ \t\n\x0B\f\r] |
\S | 非空白字符:[^\s] |
\w | 单词字符:[a-zA-Z_0-9] |
\W | 非单词字符:[^\w] |
POSIX 字符类(仅 US-ASCII) | |
\p{Lower} | 小写字母字符:[a-z] |
\p{Upper} | 大写字母字符:[A-Z] |
\p{ASCII} | 所有 ASCII:[\x00-\x7F] |
\p{Alpha} | 字母字符:[\p{Lower}\p{Upper}] |
\p{Digit} | 十进制数字:[0-9] |
\p{Alnum} | 字母数字字符:[\p{Alpha}\p{Digit}] |
\p{Punct} | 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ |
\p{Graph} | 可见字符:[\p{Alnum}\p{Punct}] |
\p{Print} | 可打印字符:[\p{Graph}\x20] |
\p{Blank} | 空格或制表符:[ \t] |
\p{Cntrl} | 控制字符:[\x00-\x1F\x7F] |
\p{XDigit} | 十六进制数字:[0-9a-fA-F] |
\p{Space} | 空白字符:[ \t\n\x0B\f\r] |
java.lang.Character 类(简单的 java 字符类型) | |
\p{javaLowerCase} | 等效于 java.lang.Character.isLowerCase() |
\p{javaUpperCase} | 等效于 java.lang.Character.isUpperCase() |
\p{javaWhitespace} | 等效于 java.lang.Character.isWhitespace() |
\p{javaMirrored} | 等效于 java.lang.Character.isMirrored() |
Unicode 块和类别的类 | |
\p{InGreek} | Greek 块(简单块)中的字符 |
\p{Lu} | 大写字母(简单类别) |
\p{Sc} | 货币符号 |
\P{InGreek} | 所有字符,Greek 块中的除外(否定) |
[\p{L}&&[^\p{Lu}]] | 所有字母,大写字母除外(减去) |
边界匹配器 | |
^ | 行的开头 |
$ | 行的结尾 |
\b | 单词边界 |
\B | 非单词边界 |
\A | 输入的开头 |
\G | 上一个匹配的结尾 |
\Z | 输入的结尾,仅用于最后的结束符(如果有的话) |
\z | 输入的结尾 |
Greedy 数量词 | |
X? | X,一次或一次也没有 |
X* | X,零次或多次 |
X+ | X,一次或多次 |
X{n} | X,恰好 n 次 |
X{n,} | X,至少 n 次 |
X{n,m} | X,至少 n 次,但是不超过 m 次 |
Reluctant 数量词 | |
X?? | X,一次或一次也没有 |
X*? | X,零次或多次 |
X+? | X,一次或多次 |
X{n}? | X,恰好 n 次 |
X{n,}? | X,至少 n 次 |
X{n,m}? | X,至少 n 次,但是不超过 m 次 |
Possessive 数量词 | |
X?+ | X,一次或一次也没有 |
X*+ | X,零次或多次 |
X++ | X,一次或多次 |
X{n}+ | X,恰好 n 次 |
X{n,}+ | X,至少 n 次 |
X{n,m}+ | X,至少 n 次,但是不超过 m 次 |
Logical 运算符 | |
XY | X 后跟 Y |
X|Y | X 或 Y |
(X) | X,作为捕获组 |
Back 引用 | |
\n | 任何匹配的 nth 捕获组 |
引用 | |
\ | Nothing,但是引用以下字符 |
\Q | Nothing,但是引用所有字符,直到 \E |
\E | Nothing,但是结束从 \Q 开始的引用 |
特殊构造(非捕获) | |
(?:X) | X,作为非捕获组 |
(?idmsux-idmsux) | Nothing,但是将匹配标志i d m s u x on - off |
(?idmsux-idmsux:X) | X,作为带有给定标志 i d m s u x on - off |
(?=X) | X,通过零宽度的正 lookahead |
(?!X) | X,通过零宽度的负 lookahead |
(?<=X) | X,通过零宽度的正 lookbehind |
(?<!X) | X,通过零宽度的负 lookbehind |
(?>X) | X,作为独立的非捕获组 |
反斜线、转义和引用
反斜线字符 ('\') 用于引用转义构造,如上表所定义的,同时还用于引用其他将被解释为非转义构造的字符。因此,表达式 \\ 与单个反斜线匹配,而 \{ 与左括号匹配。
在不表示转义构造的任何字母字符前使用反斜线都是错误的;它们是为将来扩展正则表达式语言保留的。可以在非字母字符前使用反斜线,不管该字符是否非转义构造的一部分。
根据 Java Language Specification 的要求,Java 源代码的字符串中的反斜线被解释为 Unicode 转义或其他字符转义。因此必须在字符串字面值中使用两个反斜线,表示正则表达式受到保护,不被 Java 字节码编译器解释。例如,当解释为正则表达式时,字符串字面值 "\b" 与单个退格字符匹配,而 "\\b" 与单词边界匹配。字符串字面值 "\(hello\)" 是非法的,将导致编译时错误;要与字符串 (hello) 匹配,必须使用字符串字面值 "\\(hello\\)"。
字符类
字符类可以出现在其他字符类中,并且可以包含并集运算符(隐式)和交集运算符 (&&)。并集运算符表示至少包含其某个操作数类中所有字符的类。交集运算符表示包含同时位于其两个操作数类中所有字符的类。
字符类运算符的优先级如下所示,按从最高到最低的顺序排列:
1 字面值转义 \x 2 分组 [...] 3 范围 a-z 4 并集 [a-e][i-u] 5 交集 [a-z&&[aeiou]]
注意,元字符的不同集合实际上位于字符类的内部,而非字符类的外部。例如,正则表达式 . 在字符类内部就失去了其特殊意义,而表达式 - 变成了形成元字符的范围。
行结束符
行结束符 是一个或两个字符的序列,标记输入字符序列的行结尾。以下代码被识别为行结束符:
- 新行(换行)符 ('\n')、
- 后面紧跟新行符的回车符 ("\r\n")、
- 单独的回车符 ('\r')、
- 下一行字符 ('\u0085')、
- 行分隔符 ('\u2028') 或
- 段落分隔符 ('\u2029)。
如果激活 UNIX_LINES
模式,则新行符是唯一识别的行结束符。
如果未指定 DOTALL
标志,则正则表达式 . 可以与任何字符(行结束符除外)匹配。
默认情况下,正则表达式 ^ 和 $ 忽略行结束符,仅分别与整个输入序列的开头和结尾匹配。如果激活 MULTILINE
模式,则 ^ 在输入的开头和行结束符之后(输入的结尾)才发生匹配。处于 MULTILINE
模式中时,$ 仅在行结束符之前或输入序列的结尾处匹配。
组和捕获
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:
1 ((A)(B(C))) 2 \A 3 (B(C)) 4 (C)
组零始终代表整个表达式。
之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器获取。
与组关联的捕获输入始终是与组最近匹配的子序列。如果由于量化的缘故再次计算了组,则在第二次计算失败时将保留其以前捕获的值(如果有的话)例如,将字符串 "aba" 与表达式 (a(b)?)+ 相匹配,会将第二组设置为 "b"。在每个匹配的开头,所有捕获的输入都会被丢弃。
以 (?) 开头的组是纯的非捕获 组,它不捕获文本,也不针对组合计进行计数。
Unicode 支持
此类符合 Unicode Technical Standard #18:Unicode Regular Expression Guidelines 第 1 级和 RL2.1 Canonical Equivalents。
Java 源代码中的 Unicode 转义序列(如 \u2014)是按照 Java Language Specification 的 第 3.3 节中的描述处理的。这样的转义序列还可以由正则表达式解析器直接实现,以便在从文件或键盘击键读取的表达式中使用 Unicode 转义。因此,可以将不相等的字符串 "\u2014" 和 "\\u2014" 编译为相同的模式,从而与带有十六进制值 0x2014 的字符匹配。
与 Perl 中一样,Unicode 块和类别是使用 \p 和 \P 构造编写的。如果输入具有属性 prop,则与 \p{prop} 匹配,而输入具有该属性时与 \P{prop} 不匹配。块使用前缀 In 指定,与在 InMongolian 中一样。可以使用可选前缀 Is 指定类别:\p{L} 和 \p{IsL} 都表示 Unicode 字母的类别。块和类别在字符类的内部和外部都可以使用。
受支持的类别是由 Character
类指定版本中的 The Unicode Standard 的类别。类别名称是在 Standard 中定义的,即标准又丰富。Pattern
所支持的块名称是 UnicodeBlock.forName
所接受和定义的有效块名称。
行为类似 java.lang.Character boolean 是 methodname 方法(废弃的类别除外)的类别,可以通过相同的 \p{prop} 语法来提供,其中指定的属性具有名称 javamethodname。
与 Perl 5 相比较
Pattern
引擎用有序替换项执行传统上基于 NFA 的匹配,与 Perl 5 中进行的相同。
此类不支持 Perl 构造:
-
条件构造 (?{X}) 和 (?(condition)X|Y)、
-
嵌入式代码构造 (?{code}) 和 (??{code})、
-
嵌入式注释语法 (?#comment) 和
-
预处理操作 \l \u、\L 和 \U。
此类支持但 Perl 不支持的构造:
-
Possessive 数量词,它可以尽可能多地进行匹配,即使这样做导致所有匹配都成功时也如此。
-
字符类并集和交集,如上文所述。
与 Perl 的显著不同点是:
-
在 Perl 中,\1 到 \9 始终被解释为 Back 引用;如果至少存在多个子表达式,则大于 9 的反斜线转义数按 Back 引用对待,否则在可能的情况下,它将被解释为八进制转义。在此类中,八进制转义必须始终以零开头。在此类中,\1 到 \9 始终被解释为 Back 引用,较大的数被接受为 Back 引用,如果在正则表达式中至少存在多个子表达式的话;否则,解析器将删除数字,直到该数小于等于组的现有数或者其为一个数字。
-
Perl 使用 g 标志请求恢复最后匹配丢失的匹配。此功能是由
Matcher
类显式提供的:重复执行find
方法调用可以恢复丢失的最后匹配,除非匹配器被重置。 -
在 Perl 中,位于表达式顶级的嵌入式标记对整个表达式都有影响。在此类中,嵌入式标志始终在它们出现的时候才起作用,不管它们位于顶级还是组中;在后一种情况下,与在 Perl 中类似,标志在组的结尾处还原。
-
Perl 允许错误匹配构造,如在表达式 *a 中,以及不匹配的括号,如在在表达式 abc] 中,并将其作为字面值对待。此类还接受不匹配的括号,但对 +、? 和 * 不匹配元字符有严格限制;如果遇到它们,则抛出
PatternSyntaxException
。
有关正则表达式构造行为更准确的描述,请参见 Mastering Regular Expressions, 2nd Edition,该书由 Jeffrey E. F. Friedl、O'Reilly 和 Associates 合著,于 2002 年出版。
- 从以下版本开始:
- 1.4
- 另请参见:
String.split(String, int)
,String.split(String)
, 序列化表格
字段摘要 | |
---|---|
static int |
CANON_EQ 启用规范等价。 |
static int |
CASE_INSENSITIVE
启用不区分大小写的匹配。 |
static int |
COMMENTS
模式中允许空白和注释。 |
static int |
DOTALL
启用 dotall 模式。 |
static int |
LITERAL
启用模式的字面值解析。 |
static int |
MULTILINE
启用多行模式。 |
static int |
UNICODE_CASE
启用 Unicode 感知的大小写折叠。 |
static int |
UNIX_LINES
启用 Unix 行模式。 |
方法摘要 | |
---|---|
static Pattern |
compile(String regex)
将给定的正则表达式编译到模式中。 |
static Pattern |
compile(String regex,
int flags) 将给定的正则表达式编译到具有给定标志的模式中。 |
int |
flags()
返回此模式的匹配标志。 |
Matcher |
matcher(CharSequence input)
创建匹配给定输入与此模式的匹配器。 |
static boolean |
matches(String regex, CharSequence input)
编译给定正则表达式并尝试将给定输入与其匹配。 |
String |
pattern()
返回在其中编译过此模式的正则表达式。 |
static String |
quote(String s)
返回指定 String 的字面值模式 String 。 |
String[] |
split(CharSequence input)
围绕此模式的匹配拆分给定输入序列。 |
String[] |
split(CharSequence input,
int limit) 围绕此模式的匹配拆分给定输入序列。 |
String |
toString()
返回此模式的字符串表示形式。 |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
字段详细信息 |
---|
UNIX_LINES
public static final int UNIX_LINES
- 启用 Unix 行模式。
在此模式中,.、^ 和 $ 的行为中仅识别 '\n' 行结束符。
通过嵌入式标志表达式 (?d) 也可以启用 Unix 行模式。
- 另请参见:
- 常量字段值
CASE_INSENSITIVE
public static final int CASE_INSENSITIVE
- 启用不区分大小写的匹配。
默认情况下,不区分大小写的匹配假定仅匹配 US-ASCII 字符集中的字符。可以通过指定
UNICODE_CASE
标志连同此标志来启用 Unicode 感知的、不区分大小写的匹配。通过嵌入式标志表达式 (?i) 也可以启用不区分大小写的匹配。
指定此标志可能对性能产生一些影响。
- 另请参见:
- 常量字段值
COMMENTS
public static final int COMMENTS
- 模式中允许空白和注释。
此模式将忽略空白和在结束行之前以 # 开头的嵌入式注释。
通过嵌入式标志表达式 (?x) 也可以启用注释模式。
- 另请参见:
- 常量字段值
MULTILINE
public static final int MULTILINE
- 启用多行模式。
在多行模式中,表达式 ^ 和 $ 仅分别在行结束符前后匹配,或者在输入序列的结尾处匹配。默认情况下,这些表达式仅在整个输入序列的开头和结尾处匹配。
通过嵌入式标志表达式 (?m) 也可以启用多行模式。
- 另请参见:
- 常量字段值
LITERAL
public static final int LITERAL
- 启用模式的字面值解析。
指定此标志后,指定模式的输入字符串就会作为字面值字符序列来对待。输入序列中的元字符或转义序列不具有任何特殊意义。
标志 CASE_INSENSITIVE 和 UNICODE_CASE 在与此标志一起使用时将对匹配产生影响。其他标志都变得多余了。
不存在可以启用字面值解析的嵌入式标志字符。
- 从以下版本开始:
- 1.5
- 另请参见:
- 常量字段值
DOTALL
public static final int DOTALL
- 启用 dotall 模式。
在 dotall 模式中,表达式 . 可以匹配任何字符,包括行结束符。默认情况下,此表达式不匹配行结束符。
通过嵌入式标志表达式 (?s) 也可以启用 dotall 模式(s 是 "single-line" 模式的助记符,在 Perl 中也使用它)。
- 另请参见:
- 常量字段值
UNICODE_CASE
public static final int UNICODE_CASE
- 启用 Unicode 感知的大小写折叠。
指定此标志后,由
CASE_INSENSITIVE
标志启用时,不区分大小写的匹配将以符合 Unicode Standard 的方式完成。默认情况下,不区分大小写的匹配假定仅匹配 US-ASCII 字符集中的字符。通过嵌入式标志表达式 (?u) 也可以启用 Unicode 感知的大小写折叠。
指定此标志可能对性能产生影响。
- 另请参见:
- 常量字段值
CANON_EQ
public static final int CANON_EQ
- 启用规范等价。
指定此标志后,当且仅当其完整规范分解匹配时,两个字符才可视为匹配。例如,当指定此标志时,表达式 "a\u030A" 将与字符串 "\u00E5" 匹配。默认情况下,匹配不考虑采用规范等价。
不存在可以启用规范等价的嵌入式标志字符。
指定此标志可能对性能产生影响。
- 另请参见:
- 常量字段值
方法详细信息 |
---|
compile
public static Pattern compile(String regex)
- 将给定的正则表达式编译到模式中。
- 参数:
regex
- 要编译的表达式- 抛出:
PatternSyntaxException
- 如果表达式的语法无效
compile
public static Pattern compile(String regex, int flags)
- 将给定的正则表达式编译到具有给定标志的模式中。
- 参数:
regex
- 要编译的表达式flags
- 匹配标志,可能包括CASE_INSENSITIVE
、MULTILINE
、DOTALL
、UNICODE_CASE
、CANON_EQ
、UNIX_LINES
、LITERAL
和COMMENTS
的位掩码- 抛出:
IllegalArgumentException
- 如果在 flags 中设置与定义的匹配标志不对应的位值PatternSyntaxException
- 如果表达式的语法无效
pattern
public String pattern()
- 返回在其中编译过此模式的正则表达式。
- 返回:
- 模式的源代码
toString
public String toString()
matcher
public Matcher matcher(CharSequence input)
- 创建匹配给定输入与此模式的匹配器。
- 参数:
input
- 要匹配的字符序列- 返回:
- 此模式的新匹配器
flags
public int flags()
- 返回此模式的匹配标志。
- 返回:
- 编译此模式时指定的匹配标志
matches
public static boolean matches(String regex, CharSequence input)
- 编译给定正则表达式并尝试将给定输入与其匹配。
调用此便捷方法的形式
Pattern.matches(regex, input);
Pattern.compile(regex).matcher(input).matches()
如果要多次使用一种模式,编译一次后重用此模式比每次都调用此方法效率更高。
- 参数:
regex
- 要编译的表达式input
- 要匹配的字符序列- 抛出:
PatternSyntaxException
- 如果表达式的语法无效
split
public String[] split(CharSequence input, int limit)
- 围绕此模式的匹配拆分给定输入序列。
此方法返回的数组包含输入序列的子字符串,由匹配此模式的另一子序列或输入序列的结尾终止。数组中子字符串的顺序与其在输入中出现的顺序相同。如果此模式与输入的任何子序列都不匹配,那么得到的数组仅包含一个元素,即字符串形式的输入序列。
limit 参数控制应用模式的次数,从而影响结果数组的长度。如果限制 n 大于零,那么模式至多应用 n> - 1 次,数组的长度不大于 n,并且数组的最后条目将包含除最后的匹配定界符之外的所有输入。如果 n 非正,那么将应用模式的次数不受限制,并且数组可以为任意长度。如果 n 为零,那么应用模式的次数不受限制,数组可以为任意长度,并且将丢弃尾部空字符串。
例如,输入 "boo:and:foo" 将产生以下结果及参数:
Regex
Limit
Result
: 2 { "boo", "and:foo" } : 5 { "boo", "and", "foo" } : -2 { "boo", "and", "foo" } o 5 { "b", "", ":and:f", "", "" } o -2 { "b", "", ":and:f", "", "" } o 0 { "b", "", ":and:f" } - 参数:
input
- 要拆分的字符序列limit
- 结果阈值,如上文中所述- 返回:
- 根据围绕此模式的匹配来拆分输入后所计算的字符串数组
split
public String[] split(CharSequence input)
- 围绕此模式的匹配拆分给定输入序列。
此方法的工作方式类似于使用给定的输入序列和限制参数零调用两参数 (java.lang.CharSequence, int) split} 方法。因此,得到的数组中不包括尾部空字符串。
例如,输入 "boo:and:foo" 将产生以下结果及表达式:
Regex
Result
: { "boo", "and", "foo" } o { "b", "", ":and:f" } - 参数:
input
- 要拆分的字符序列- 返回:
- 根据围绕此模式的匹配来拆分输入后所计算的字符串数组
quote
public static String quote(String s)
- 返回指定
String
的字面值模式String
。此方法产生一个
输入序列中的元字符和转义序列不具有任何特殊意义。String
,可以将其用于创建与字符串s
匹配的Pattern
,就好像它是字面值模式一样。 - 参数:
s
- 要字面值化的字符串- 返回:
- 字面值字符串替换
- 从以下版本开始:
- 1.5
版权所有 2007 Sun Microsystems, Inc. 保留所有权利。 请遵守许可证条款。另请参阅文档重新分发政策。
Matcher 类 :
Matcher 方法如下:
Matcher | appendReplacement(StringBuffer sb, String replacement) 将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个 StringBuffer 对象里。 |
---|---|
StringBuffer | appendTail(StringBuffer sb) 将最后一次匹配工作后剩余的字符串添加到一个 StringBuffer 对象里。 |
int | end() 返回当前匹配的子串的最后一个字符在原目标字符串中的索引位置 。 |
int | end(int group) 返回与匹配模式里指定的组相匹配的子串最后一个字符的位置。 |
boolean | find() 尝试在目标字符串里查找下一个匹配子串。 |
boolean | find(int start) 重设 Matcher 对象,并且尝试在目标字符串里从指定的位置开始查找下一个匹配的子串。 |
String | group() 返回当前查找而获得的与组匹配的所有子串内容 |
String | group(int group) 返回当前查找而获得的与指定的组匹配的子串内容 |
int | groupCount() 返回当前查找所获得的匹配组的数量。 |
boolean | lookingAt() 检测目标字符串是否以匹配的子串起始。 |
boolean | matches() 尝试对整个目标字符展开匹配检测,也就是只有整个目标字符串完全匹配时才返回真值。 |
Pattern | pattern() 返回该 Matcher 对象的现有匹配模式,也就是对应的 Pattern 对象。 |
String | replaceAll(String replacement) 将目标字符串里与既有模式相匹配的子串全部替换为指定的字符串。 |
String | replaceFirst(String replacement) 将目标字符串里第一个与既有模式相匹配的子串替换为指定的字符串。 |
Matcher | reset() 重设该 Matcher 对象。 |
Matcher | reset(CharSequence input) 重设该 Matcher 对象并且指定一个新的目标字符串。 |
int | start() 返回当前查找所获子串的开始字符在原目标字符串中的位置。 |
int | start(int group) 返回当前查找所获得的和指定组匹配的子串的第一个字符在原目标字符串中的位置。 |
(光看方法的解释是不是很不好理解?不要急,待会结合例子就比较容易明白了)
一个 Matcher 实例是被用来对目标字符串进行基于既有模式(也就是一个给定的 Pattern 所编译的正则表达式)进行匹配查找的,所有往 Matcher 的输入都是通过 CharSequence 接口提供的,这样做的目的在于可以支持对从多元化的数据源所提供的数据进行匹配工作。
我们分别来看看各方法的使用:
★ matches()/lookingAt ()/find():
一个 Matcher 对象是由一个 Pattern 对象调用其 matcher() 方法而生成的,一旦该 Matcher 对象生成 , 它就可以进行三种不同的匹配查找操作:
- matches() 方法尝试对整个目标字符展开匹配检测,也就是只有整个目标字符串完全匹配时才返回真值。
- lookingAt () 方法将检测目标字符串是否以匹配的子串起始。
- find() 方法尝试在目标字符串里查找下一个匹配子串。
以上三个方法都将返回一个布尔值来表明成功与否。
★ replaceAll ()/appendReplacement()/appendTail():
Matcher 类同时提供了四个将匹配子串替换成指定字符串的方法:
- replaceAll()
- replaceFirst()
- appendReplacement()
- appendTail()
replaceAll() 与 replaceFirst() 的用法都比较简单,请看上面方法的解释。我们主要重点了解一下 appendReplacement() 和 appendTail() 方法。
appendReplacement(StringBuffer sb, String replacement) 将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个 StringBuffer 对象里,而 appendTail(StringBuffer sb) 方法则将最后一次匹配工作后剩余的字符串添加到一个 StringBuffer 对象里。
例如,有字符串 fatcatfatcatfat, 假设既有正则表达式模式为"cat",第一次匹配后调用 appendReplacement(sb,"dog"), 那么这时 StringBuffer sb 的内容为 fatdog,也就是 fatcat 中的 cat 被替换为 dog 并且与匹配子串前的内容加到 sb 里,而第二次匹配后调用 appendReplacement(sb,"dog"),那么 sb 的内容就变为 fatdogfatdog,如果最后再调用一次 appendTail(sb), 那么 sb 最终的内容将是 fatdogfatdogfat。
还是有点模糊?那么我们来看个简单的程序:
// 该例将把句子里的"Kelvin"改为"Kevin" import java.util.regex.*; public class MatcherTest{ public static void main(String[] args) throws Exception { // 生成 Pattern 对象并且编译一个简单的正则表达式"Kelvin" Pattern p = Pattern.compile("Kevin"); // 用 Pattern 类的 matcher() 方法生成一个 Matcher 对象 Matcher m = p.matcher("Kelvin Li and Kelvin Chan are both working in " + "Kelvin Chen's KelvinSoftShop company"); StringBuffer sb = new StringBuffer(); int i=0; // 使用 find() 方法查找第一个匹配的对象 boolean result = m.find(); // 使用循环将句子里所有的 kelvin 找出并替换再将内容加到 sb 里 while(result) { i++; m.appendReplacement(sb, "Kevin"); System.out.println("第"+i+"次匹配后 sb 的内容是:"+sb); // 继续查找下一个匹配对象 result = m.find(); } // 最后调用 appendTail() 方法将最后一次匹配后的剩余字符串加到 sb 里; m.appendTail(sb); System.out.println("调用 m.appendTail(sb) 后 sb 的最终内容是 :"+ sb.toString()); } }
最终输出结果为:
第 1 次匹配后 sb 的内容是:Kevin
第 2 次匹配后 sb 的内容是:Kevin Li and Kevin
第 3 次匹配后 sb 的内容是:Kevin Li and Kevin Chan are both working in Kevin
第 4 次匹配后 sb 的内容是:Kevin Li and Kevin Chan are both working in Kevin Chen's Kevin
调用 m.appendTail(sb) 后 sb 的最终内容是:Kevin Li and Kevin Chan are both working in Kevin Chen's KevinSoftShop company.
看了上面这个例程是否对 appendReplacement(),appendTail() 两个方法的使用更清楚呢,如果还是不太肯定最好自己动手写几行代码测试一下。
★ group()/group(int group)/groupCount():
该系列方法与我们在上篇介绍的 Jakarta-ORO 中的 MatchResult .group() 方法类似 ( 有关 Jakarta-ORO 请参考上篇的内容 ),都是要返回与组匹配的子串内容,下面代码将很好解释其用法:
import java.util.regex.*; public class GroupTest{ public static void main(String[] args) throws Exception { Pattern p = Pattern.compile("(ca)(t)"); Matcher m = p.matcher("one cat,two cats in the yard"); StringBuffer sb = new StringBuffer(); boolean result = m.find(); System.out.println("该次查找获得匹配组的数量为:"+m.groupCount()); for(int i=1;i<=m.groupCount();i++){ System.out.println("第"+i+"组的子串内容为: "+m.group(i)); } } }
输出为:
该次查找获得匹配组的数量为:2
第 1 组的子串内容为:ca
第 2 组的子串内容为:t
Matcher 对象的其他方法因比较好理解且由于篇幅有限,请读者自己编程验证。
一个检验 Email 地址的小程序:
最后我们来看一个检验 Email 地址的例程,该程序是用来检验一个输入的 EMAIL 地址里所包含的字符是否合法,虽然这不是一个完整的 EMAIL 地址检验程序,它不能检验所有可能出现的情况,但在必要时您可以在其基础上增加所需功能。
import java.util.regex.*; public class Email { public static void main(String[] args) throws Exception { String input = args[0]; // 检测输入的 EMAIL 地址是否以 非法符号"."或"@"作为起始字符 Pattern p = Pattern.compile("^\\.|^\\@"); Matcher m = p.matcher(input); if (m.find()){ System.err.println("EMAIL 地址不能以'.'或'@'作为起始字符"); } // 检测是否以"www."为起始 p = Pattern.compile("^www\\."); m = p.matcher(input); if (m.find()) { System.out.println("EMAIL 地址不能以'www.'起始"); } // 检测是否包含非法字符 p = Pattern.compile("[^A-Za-z0-9\\.\\@_\\-~#]+"); m = p.matcher(input); StringBuffer sb = new StringBuffer(); boolean result = m.find(); boolean deletedIllegalChars = false; while(result) { // 如果找到了非法字符那么就设下标记 deletedIllegalChars = true; // 如果里面包含非法字符如冒号双引号等,那么就把他们消去,加到 SB 里面 m.appendReplacement(sb, ""); result = m.find(); } m.appendTail(sb); input = sb.toString(); if (deletedIllegalChars) { System.out.println("输入的 EMAIL 地址里包含有冒号、逗号等非法字符,请修改"); System.out.println("您现在的输入为 : "+args[0]); System.out.println("修改后合法的地址应类似 : "+input); } } }
例如,我们在命令行输入:java Email www.kevin@163.net
那么输出结果将会是:EMAIL 地址不能以'www.'起始
如果输入的 EMAIL 为 @kevin@163.net
则输出为:EMAIL 地址不能以'.'或'@'作为起始字符
当输入为:cgjmail#$%@163.net
那么输出就是:
输入的 EMAIL 地址里包含有冒号、逗号等非法字符,请修改 您现在的输入为 : cgjmail#$%@163.net 修改后合法的地址应类似 : cgjmail@163.net
总结:
本文介绍了 jdk1.4.0-beta3 里正则表达式库 --java.util.regex 中的类以及其方法,如果结合与上一篇中所介绍的 Jakarta-ORO API 作比较,读者会更容易掌握该 API 的使用,当然该库的性能将在未来的日子里不断扩展,希望获得最新信息的读者最好到及时到 SUN 的网站去了解。