java正则表达式

正则表达式

正则表达式是处理字符串的强大工具,它并不是java的特性.但是java有一套工具类提供了正则表达式的匹配功能.

用途

  1. 字符串匹配
  2. 字符串查找
  3. 字符串替换

Java类

java中正则表达式主要包括两个类:

  • Pattern: 此对象是一个正则表达式的编译表示.此类没有共有的构造方法,只能通过静态编译方法来获得一个Pattern对象.比如Pattern.compile(“\d”); 这个样子.参数就是要编译的正则表达式.
  • Matcher: 是对输入字符串进行解释和匹配的引擎,它也没有公共的构造方法,只能通过Pattern对象的match方法来获得一个Matcher对象

Java中的正则表达式语法

首先说明java 中的正则表达式与普通的不一样,java中 ‘\‘ 表示的是要插入一个正则表达式的反斜杠,所以之后的字符具有特殊意义.所以在java中一个’\‘代表着其他语言中的一个’\’.为什么这么做呢,是因为java中字符串是不能有’\’的,如果有的话就必须得插入’\‘表示转义.所以在java字符串中就有了’\‘表示正则中的一个’\’了.这是java语言要求的.
下面来看一下具体用法

字符 说明 举例
\ 将下一个字符标记为特殊字符,就是转义字符. 例如 ‘\n’ 匹配 换行, ‘\\‘匹配’\‘.
^ 匹配字符流的第一个字符 例如”^d.*” 匹配 以d开头的字符串
$ 匹配字符流的最后一个字符  如上 
* 零次或多次匹配前一个字符 例如 “zo*” 匹配 “zoo” 和 “z” “zo”
+ 一次或多次匹配前一个字符 例如 “zo+” 匹配 “zoo” 和 “zo” 但是不匹配 “z”
? 匹配零次或一次之前的字符 例如 “1?” 匹配”1” 和 “” 空
{n} n为非负数,正好匹配前一个字符n次 例如 “o{2}” 匹配 “oo”
{n,} n为非负数,匹配至少n此 如上
{n,m} 匹配n到m次之前的字符 如上
. 匹配任意字符 例如 “a.” 匹配 “ab” “ac” “ad”等
(pattern) 匹配 pattern 并捕获该匹配的子表达式. 例如 “(ab?)” 匹配 “a” “ab”
x|y 匹配x或者y字符 “a|b” 匹配 “a” 或 “b”
[^abc] 反向字符集 匹配非括号内的字符 “[^123]” 匹配不是字符1 2 3 的所有字符
[a-z] 匹配a到z之间的所有字符
\b  边界字符  例如 “er\b” 匹配 “never”中的er,但是不匹配”verb”中的er
\B 非边界字符 和上面反过来
\d 匹配数字字符
\D 匹配非数字字符
\n 换行符
\s 匹配任意空白字符 包括空格符,制表符,换页符
\S 匹配任意非空白字符
\w 匹配任意字类字符 
\W 匹配任意非字类字符

Pattern

具体看看Pattern的用法,对象如其名,是一个匹配模式的编译表示.在java中不能直接构造出来,只能通过静态方法complie()来获取Pattern实例.

1
2
Pattern pattern =  Pattern.compile("\\d+");
System.out.println(pattern.pattern()); // 输出 \d+

此语句就返回一个匹配模式,此模式匹配全部的数字.

Pattern.split(CharSequence input)

Pattern 有一个split方法,这个方法与String.split()方法是一样的.返回用指定字符分割的字符数组

1
2
3
Pattern pattern =  Pattern.compile("\\d+");
String[] strs = pattern.split("nihao123hello123word");
[nihao, hello, word] // 输出

matches(String regex, CharSequence input)

这个方法是返回一个boolean值,判断输入是否与指定模式匹配.这里匹配是要全部匹配

1
2
3
Pattern.matches("\\d+","12312312");  //true
Pattern.matches("\\d+","123a12312"); //false a不匹配
System.out.println(Pattern.matches("\\d+","")); // false ,+ 说明一个或多个,空不匹配

matcher(CharSequence input)

返回一个Matcher类,Matcher类提供了比Pattern更为多的功能,它能够匹配多次,并且有分组支持.

Matcher类方法

matchers() / lookingAt() / find()

Matcher类提供了三个匹配操作方法,三个方法都返回boolean值,匹配到时返回true,匹配不到返回false .
matchers()方法是对整个字符串进行匹配,只有整个字符串都匹配了才返回true
lookingAt() 只是对开头的字符进行匹配,只要开头有符合的,就返回true
find()对字符串匹配,匹配到的字符串可以在任意位置.

1
2
3
4
5
6
7
8
9
10
11
12
13
Pattern pattern =  Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("223322");
matcher.matches(); // true
matcher.lookingAt(); // true
matcher.find(); // true
Matcher m2 = pattern.matcher("2233dd");
m2.matches(); // false 全部匹配才可以
m2.lookingAt(); // true 开头有匹配的可以
m2.find(); // true 任意地方匹配
Matcher m3 = pattern.matcher("dd2233");
m3.matches(); // false
m3.lookingAt(); // false 开头没有匹配
m3.find(); // true 任意有匹配可以

start() / end() / group()

使用matchers(),lookingAt(),find()方法后就可以使用这三个方法得到更加详细的信息
start() 返回匹配的子字符串在索引中的位置
end() 返回匹配的子字符串的最后一个字符在索引的位置
group() 返回匹配到的子字符串. 分组是在自己定义的匹配模式中定义的.用()包起来的.
这里分组有一个规定 :
捕获组是通过从左至右计算其开括号来编号,第一个括号编号从1开始.例如表达式中((A)(B(C))).编号从从1开始是如下的:

  1. ((A)(B(C)))
  2. (A)
  3. (B(C))
  4. (C)

代码实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 这里只介绍group操作,可以把group操作想成是m.group()操作看成是s.substring(m.start(),m.end());
Pattern p = Pattern.compile("(\\d+)((abc)+)");
Matcher matcher1 = p.matcher("900abcabc");
System.out.println(matcher1.matches()); // true 匹配到了整个字符串
System.out.println(matcher1.group()); // 返回整个字符串
System.out.println(matcher1.group(1)); // 第一个匹配的 全部的数字 所以是 900
System.out.println(matcher1.group(2)); // 第二个匹配的 abcabc
System.out.println(matcher1.group(3)); // 第三个括号 一个abc

// 下面看lookingAt()方法
Pattern p1 = Pattern.compile("(\\d+)(abc)");
Matcher matcher2 = p1.matcher("900abcbbd");
matcher2.lookingAt(); // true looking只需要匹配开头就可以了.所以这里是true,如果用matches则返回false
System.out.println(matcher2.group(1)); // 900 匹配第一个括号中的内容
System.out.println(matcher2.group(2)); // abc 后面的则不匹配

find方法,find方法比较不一样,所以需要单独来讲

1
2
3
4
5
6
7
8
9
10
        Pattern p2 = Pattern.compile("(\\d+)(a+)");
Matcher matcher3 = p2.matcher("900aa bcbb900aa bcbb900aa bcbbabc");
while (matcher3.find()){
System.out.println(matcher3.group());
}

输出
900aa
900aa
900aa

find方法将会找到整个串中所有符合的子串.当然也可以使用group(1)匹配第一个分组,从而找到所有的字符串.在这里有一个点就是因为find()方法会匹配整个字符串符合模式的子串.所以每次调用find()方法,就会找到下一个匹配此模式的子串.所以在调用了一次find()方法就需要在调用一次group()方法来获得所匹配的子串.这是因为在matcher中记录了一个当前匹配的位置,下一次在匹配的时候会从当前位置开始进行匹配.

appendReplacement(StringBuffer sb, String replacement) 和 appendTail(StringBuffer sb)

appendReplacement这个方法主要是为了用来为字符串做替换的.通过将匹配到的字符串替换成指定的字符串到字符串缓冲区.appendTail从添加位置开始从字符序列读取字符然后加入到缓冲区.一般是用来给appendReplacement方法替换过之后调用它来复制剩余的序列.

1
2
3
4
5
6
7
8
9
10
11
Pattern p3 = Pattern.compile("cat");
StringBuffer sb = new StringBuffer();
Matcher matcher4 = p3.matcher("one cat and two cats in the word");
while (matcher4.find()){
matcher4.appendReplacement(sb,"dog");
}
// 在这里输出的结果是最后一次匹配替换过后的字符串 one dog and two dog
matcher4.appendTail(sb); // 这里通过appendTail()进行收尾工作,将结尾的字符添加到缓冲区中.
System.out.println(sb.toString());
输出
one dog and two dogs in the word