正则表达式-java上的应用

在上一篇正则表达式中介绍了正则表达式的规则,这篇主要讲正则表达式在Java中几个类的使用。
JDK中,与正则表达式有关的类都在java.util,regex,主要是Pattern类和Matcher类,String类中也有分别方法可以使用正则表达式。
文章主要结合《java编程思想》和Java的开发文档,选取了日常开发中经常用到的方法进行分析,再自己编写用例熟悉其用法以及验证理解是否正确。

\在正则表达式中用于转义,由于java对其有特殊的处理方式,如果需要插入一个\需要使用\\,如正则表达式中的\d在java中为\\d,插入一个普通的\在java中为\\\\

String类

匹配

boolean matches(String regex)方法

判断整个字符串是否匹配regex表示的正则表达式

1
2
3
4
5
6
7
public static void main(String[] args) {
System.out.println("12345A".matches("\\d"));
System.out.println("12345".matches("\\d+"));
}
//output
false
true

替换

String replace(char oldchar,char newchar)
String replace(CharSequence target,CharSequence replacement)

replace() 没有用到正则表达式,第一个参数(被替换的字符)和第二个参数(替换的字符)都是普通字符

1
2
3
4
5
6
System.out.println(".1212345".replace(".", "A"));
// \\. 在这里没有特殊的意义,作为普通的字符
System.out.println("\\.1212345".replace("\\.", "A"));
//output
A1212345
A1212345
String replaceFirst(String regex,String replacement)

参数replacement根据regex正则表达式替换掉第一个匹配成功的部分

1
2
3
System.out.println("1212345".replaceFirst("\\d", "A"));
//output
A212345
String replaceAll(String regex,String replacement)

参数replacement根据regex正则表达式替换掉所有匹配成功的部分

1
2
3
4
5
6
// 对比replace的区别,replaceAll的第一个参数,是代表任意字符
System.out.println(".1212345".replaceAll(".", "A"));
System.out.println("1212345B".replaceAll("\\d", "A"));
//output
AAAAAAAA
AAAAAAAB

分割

String[] split(String regex)

根据regex进行分割,匹配到的字符不输出

1
2
3
System.out.println(Arrays.toString("12#12#345#B".split("#")));
//output
[12, 12, 345, B] //#分割符不输出
String[] split(String regex,int limit)

limit限制了分割后的数组的数量,达到限制的数量后不再进行分割,直接输出

1
2
3
4
// 限制了匹配后输出数组的最大长度为3
System.out.println(Arrays.toString("12#12#345#B".split("#",3)));
//output
[12, 12, 345#B]

Pattern 和 Matcher类

由于String的功能比较有限,在一些情况下,我们需要构造功能强大的正则表达式对象,可以使用 java.util.regex 包中的Pattern类和Matcher类

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
//通过调用静态方法创建一个Pattern类
//也可以通过 Pattern.compile(String regex,int flag); 制定匹配模式标志
Pattern pattern = Pattern.compile("a*b");
//通过matcher创建Matcher类
Matcher matcher = pattern.matcher("aaaaab");
System.out.println(matcher.matches());

//也可以写成
System.out.println(Pattern.matches("a*b", "aaaaab"));

//output
true

Pattern类

查找

static Pattern compile(String regex)

通过设置正则表达式参数regex生成一个Pattern对象

Matcher matcher(CharSequence input)

通过传入要检索的字符串参数生成一个Matcher对象

static boolean matches()

检查regex是否匹配整个字符串,regex可以通过Pattern.compile(regex)设置,也可以直接通过Pattern类中的matches(regex,input)设置,可以参考上面的范例。

static Pattern compile(String regex,int flag)

compile()的另外一个方法,flag是Pattern中的标记,用于调整匹配的行为,常用的标记如下:

http://phulrg7q8.bkt.clouddn.com/15424262454704.jpg-wtmark

编译标记 效果
Pattern.CANON_EQ 默认情况下,匹配不考虑采用规范等价。指定此标志后,当且仅当其完整规范分解匹配时,两个字符才可视为匹配。例如,当指定此标志时,表达式 “a\u030A” 就会匹配字符串?。
Pattern.CASE_INSENSITIVE(?i) 默认情况下,不区分大小写的匹配假定只是US-ASCII 字符集中的字符才能进行。指定此标志后,允许模式匹配不必考虑大小写。
Pattern.MULTILINE(?m) 默认情况下,表达式 ^ 和 $ 仅匹配输入的完整字符串的开始结束。指定此标志后,在多行模式下,表达式 ^ 和 $ 分别匹配一行的开始和结束。
Pattern.DOTALL(?s) 默认情况下,”.”表达式不匹配行终结符。指定此标志后,表达式“.”匹配所有字符
Pattern.COMMENTS(?x) 指定此标志后,空格符将被忽略掉,并且以#开始直到行末的注释也会被忽略掉。
String flags() 和 int pattern()

flags()返回Pattern设置的flag,pattern()返回Pattern设置的regex

1
2
3
4
5
6
7
8
9
//CANON_EQ = 0x80;十六进制转化为十进制为128
Pattern pattern = Pattern.compile("\\d",Pattern.CANON_EQ);
//flags()返回Pattern设置的flag
System.out.println(pattern.flags());
//pattern()返回Pattern设置的regex
System.out.println(pattern.pattern());
//output
128
\d

替换

Pattern类中的split()方法与String类中的使用一致,可以参考上面的String类

matcher类

查找

boolean lookingat()

lookingAt()与matches()和find()类似,不过其只对前面的字符串进行匹配,只有匹配到的字符串在最前面才返回true

1
2
3
4
5
6
7
8
9
Pattern pattern = Pattern.compile("\\d");
Matcher matcher = pattern.matcher("12A12B");
System.out.println(matcher.lookingAt());
Matcher matcher2 = pattern.matcher("A1212B");
System.out.println(matcher2.lookingAt());

//output
true
false
boolean find()

遍历字符串,查找多个匹配,匹配到就返回true,否则为false

1
2
3
4
5
6
7
8
9
10
11
12
Pattern pattern = Pattern.compile("\\d");
Matcher matcher = pattern.matcher("12A12B");
//find()像迭代器那样向前遍历字符串,匹配到的话返回true
while(matcher.find()){
//group()返回前一次匹配操作(如find())的第0组
System.out.println(matcher.group());
}
//output
1
2
1
2
boolean find(int index)

find带参数,表示该字符串中字符的位置,并以其作为搜索的起点

String group()

group表示组,group( )返回前一次匹配操作的第0组,也可以通过group(int i)指定返回在前一次匹配操作期间指定的组号,如果匹配成功,但是指定的组没有匹配输入字符串的任何部分,则返回null。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("12AA34B");
int i = 0;
while (matcher.find(i)) {
System.out.println(i+" "+matcher.group());
i++;
}
//output
0 12 //i=0,匹配的是12AA34B,匹配到12
1 2 //i=1时,匹配的是2AA34B,匹配到2
2 34 //i=2时,匹配的是AA34B,匹配到34
3 34 //i=3时,匹配的是A34B,匹配到34
4 34 //i=4时,匹配的是34B,匹配到34
5 4 //i=5时,匹配的是4B,匹配到4
int groupCount()

返回分组的数目,第0组不包括在内

int start(int group)

返回在前一次匹配操作中寻找到的组的起始索引,start()和start(0)一致,为第0个分组。

int end(int group)

返回在前一次匹配操作中寻找到的组的最后一个字符索引加一的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Matcher matcher = Pattern.compile("(\\d+)(\\D+(\\d+))").matcher("12#34#567#B");
//返回分组的数目
System.out.println("groupCount = "+matcher.groupCount());
while(matcher.find()){
System.out.println("group() = "+matcher.group()+" start() = "+matcher.start()+" end = "+matcher.end());
for(int j=0;j <= matcher.groupCount();j++){
System.out.println("grounp("+j+") "+matcher.group(j) );
System.out.println("start("+j+") = "+matcher.start(j)+" end("+j+") = "+matcher.end(j));
}
}

//output
groupCount = 3
group() = 12#34 start() = 0 end = 5
grounp(0) 12#34
start(0) = 0 end(0) = 5
grounp(1) 12
start(1) = 0 end(1) = 2
grounp(2) #34
start(2) = 2 end(2) = 5
grounp(3) 34
start(3) = 3 end(3) = 5

注意:

1
2
3
4
5
6
7
8
9
10
11
Matcher matcher2 = Pattern.compile("((\\d+)(\\D+(\\d+)))").matcher("12#34#567#B"); 

//output
groupCount = 4 //最外层添加了一个括号,分组数目添加1

((\\d+)(\\D+(\\d+)))
0组:((A)(B(C)))
1组:((A)(B(C)))
2组:(A)
3组:(B(C))
4组:(C)
Matcher reset(CharSequence input)

将现有的Matcher对象应用于一个新的字符序列中,如果采用不带参数的reset()方法,可以将Mathcer对象重新设置到当前字符序列的起始位置。

1
2
3
4
5
6
7
8
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("12345A");
System.out.println(matcher.matches());
matcher.reset("12345");
System.out.println(matcher.matches());
//output
false
true
Matcher appendReplacement(StringBuffer sb,String replacement)
Matcher appendTail(StringBuffer sb)

appendReplacement()和replaceFirst()以及replaceAll()都是用来进行替代操作,区别在于不是使用一个固定的字符串replacement一次性进行替换,而是采用渐进式的替换。appendTail(),在执行了一次或多次appendReplacement()之后,调用此方法可以将输入字符串余下的部分复制到sb中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Pattern pattern = Pattern.compile("[aeiou]");
Matcher matcher = pattern.matcher("Hello world");
StringBuffer sb = new StringBuffer();
while(matcher.find()){
//对每一次的replacement进行操作再执行替换
atcher.appendReplacement(sb, matcher.group().toUpperCase());
}
System.out.println(sb);
//将剩下部分rld复制到sb中
matcher.appendTail(sb);
System.out.println(sb.toString());
//output
HEllO wO
HEllO wOrld

公众号:亦袁非猿

欢迎关注,交流学习