JAVA 正则表达式
1. 定义
1.1 基础定义
- 正则表达式定义了字符串的模式
- 正则表达式可以用来搜索、编辑或处理文本
- 正则表达式并不仅限于编程语言,但是在每种编程语言中有细微差别
1.2 Java中的正则表达式
在Sun的JDK1.4版本中,JAVA自带了支持正则表达式的包,即java.util.regex包
2. 基础
2.1 元字符
代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符(linux:\n win:\r\n) |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任何空白字符,是[ \t\n\x0b\r\f](开头有空格)的简写 |
\d | 匹配数字,是[0-9]的简写 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
\b | 匹配字符串的结束 |
2.2 重复
代码/语法 | 说明 |
---|---|
* | 重复零次或更多次(任意次) |
+ | 重复一次或更多次(至少一次) |
? | 重复零次或一次(至多一次) |
重复n次 | |
重复n次或更多次 | |
重复n到m次 |
2.3 字符类
- 匹配自定义字符集,如:[.?!]匹配标点字符"."或"?"或"!"
- [0-9]与\d等同
- [a-z0-9A-Z_]与\w等同(仅考虑英文)
2.4 分支条件
使用|把不同的规则分别表示
如:0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种连字符号分割的电话号码,一种是三位区号,8位本地号(如012-87654321);一种是4位区号,7位本地号(如:0123-7654321)
2.5 反义
代码/语法 | 说明 |
---|---|
\W | 匹配任意不是字母、数字、下划线、汉字的字符,等同于[^\w] |
\S | 匹配任意不是空白的字符 |
\D | 匹配任意不是数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
2.6 复选例子
- [abc] 复选集定义,匹配a,b,c
- [^abc]匹配除了a,b,c以外的所有字符
- [a-d1-7]范围匹配,匹配字母a-d和数字1-7的单字符,即不匹配d1
2.7 分组和反向引用
小括号()可以达到对正则表达式进行分组的效果。
模式分组后会在正则表达式中创建反向引用。反向引用会保存匹配模式分组的字符串片段,这使得我们可以获取并使用这个。字符串片段。
在以正则表达式替换字符串的语法中,是通过$来引用分组的反向引用,$0是匹配完整模式的字符串(注意在JavaScript中是用$&表示);$1是第一个分组的反向引用;$2是第二个分组的反向引用,以此类推。
示例:
@Test
public void regexGroup(){
// 去除单词与“.”和","之间的空格
String str = "Hello , World .";
String pattern = "(\\w)(\\s)([.,])";
// $0匹配“(\w)(\s)([.,])”,结果为“o.空格,”和“d空格.”
// $1匹配“(\w)” 结果为“o”和“d”
// $2匹配”(\s)“ 结果为”空格“和”空格“
// $3匹配”([.,])“ 结果为”,“和”.“
//Hello, World.
System.out.println(str.replaceAll(pattern,"$1$3"));
//Hello(hhh), World(hhh).
System.out.println(str.replaceAll(pattern,"$1(hhh)$3"));
}
上面的例子中,使用了[.]来匹配普通字符”.“,而不是使用[\\.]。因为正则表达式[]中的".",会自动处理为[\.],即普通字符"."来处理。
2.8 分组的反向引用副本
Java中可以使用"?
@Test
public void name(){
String str = "@Vitcou nice to meet you";
//String str = "@Vitcou @123 nice to meet you";
// 保存一个副本
Pattern pattern = Pattern.compile("@(?<first>\\w+\\s+)");
Matcher matcher = pattern.matcher(str);
while (matcher.find()){
System.out.println(matcher.group());
System.out.println(matcher.group(1));
System.out.println(matcher.group(0));
System.out.println(matcher.group("first"));
}
}
@Vitcou
Vitcou
@Vitcou
Vitcou
2.9 指定正则表达式的模式
可以在正则表达式使用修饰符指定模式
- (?i)正则表达式忽略大小写
- (?s)表示单行模式("single line mode"),使用正则的"."表达式匹配所有字符,包括换行符
- (?m)表示多行模式("multi-line mode"),使用正则的"^"和"$"匹配字符串每行的开始和结束
2.10 易错点示例
- [jpg|png]代表匹配j或p或g或p或n或g中的任意字符
- (jpg|png)代表匹配jpg或png
3. Java中字符串正则表达式处理方法
3.1 处理方法
在Java中String有四个内置的运行正则表达式的方法,分别是matchers()、split()、replaceFirst(pattern,replacement)、replaceAll(pattern,replacement)
方法 | 描述 |
---|---|
str.matches("pattern") | 仅当正则匹配整个字符串时返回true |
str.split("pattern") | 按照匹配的正则表达式切片字符串 |
str.replaceFirst("pattern","replacement") | 替换第一个匹配的字符串片段 |
str.replaceAll(”pattern",“replacement”) | 替换所有匹配的字符串片段 |
3.2 代码示例
@Test
public void javaRegexTest(){
System.out.println("vitcou".matches("vitcou"));
System.out.println("---------------");
String[] array = "v i t c o u".split("\\s");
for (String s : array) {
System.out.println(s);
}
System.out.println("---------------");
System.out.println("v i t c o u".replaceFirst("\\s","-"));
System.out.println("---------------");
System.out.println("v i t c o u".replaceAll("\\s","-"));
System.out.println("---------------");
}
4. 模式和匹配
Java中使用正则表达式需要使用到两个类
import java.util.regex.Matcher;
import java.util.regex.Pattern;
第一步,通过正则表达式创建模式对象Pattern;
第二步,通过模式对象Pattern,根据指定字符串匹配对象Matcher;
第三步,通过匹配对象Matcher,根据正则表达式操作字符串;
示例代码:
@Test
public void patternAndMatcher(){
String str = "Hello Vitcou";
String regex = "\\w+";
Pattern pattern = Pattern.compile(regex);
// Java中忽略大小写的两种写法
//Pattern pattern = Pattern.compile("\\w+",Pattern.CASE_INSENSITIVE);
// 推荐写法
//Pattern pattern = Pattern.compile("(?i)\\w+");
Matcher matcher = pattern.matcher(str);
// 遍历所有匹配的序列
while (matcher.find()){
System.out.println("start:"+matcher.start()+"---"+"end:"+matcher.end());
System.out.println("group:"+matcher.group());
}
// 创建两个模式,将空格替换为"---"(将匹配内容替换成指定内容)
Pattern replace = Pattern.compile("\\s+");
Matcher matcher2 = replace.matcher(str);
System.out.println("after replace:"+matcher2.replaceAll("---"));
}
5. 参考例子
5.1 中文字匹配
@Test
public void regexChinese(){
String str = "你所做的便是你所拥有的";
//Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]");
Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher matcher = pattern.matcher(str);
while (matcher.find()){
System.out.println(matcher.group());
}
}
5.2 数字匹配
@Test
public void numbers(){
String str = "1990\n2009\n2017";
// 这里应用了 (?m) 的多行匹配模式,只为方便我们测试输出
// "^1990$|^199[1-9]$|^20[0-1][0-6]$|^2017$" 为判断 1990-2017 正确的正则表达式
// 这里也说明匹配语法是单个字符
Pattern pattern = Pattern.compile("(?m)^1990$|^199[1-9]$|^200[0-9]$|^201[0-6]$|^2017$");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
5.3 贪婪与非贪婪模式匹配标签内内容
贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。非贪婪模式只被部分NFA引擎所支持。
属于贪婪模式的量词,也叫做匹配优先量词,包括:
“{m,n}”、“{m,}”、“?”、“*”和“+”。
在一些使用NFA引擎的语言中,在匹配优先量词后加上“?”,即变成属于非贪婪模式的量词,也叫做忽略优先量词,包括:
“{m,n}?”、“{m,}?”、“??”、“*?”和“+?”。
从正则语法的角度来讲,被匹配优先量词修饰的子表达式使用的就是贪婪模式,如“(Expression)+”;被忽略优先量词修饰的子表达式使用的就是非贪婪模式,如“(Expression)+?”。
参考示例:
@Test
public void greedy(){
String str = "<div>文章标题</div><div>发布时间</div>";
// 贪婪模式
Pattern pattern = Pattern.compile("<div>(?<title>.+)</div>");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group("title"));
}
System.out.println("--------------");
// 非贪婪模式,在匹配优先量量词后面加上"?",即变成非贪婪模式的量词,也叫忽略优先量词
pattern = Pattern.compile("<div>(?<title>.+?)</div>");
matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group("title"));
}
}
文章标题</div><div>发布时间
--------------
文章标题
发布时间
参考:
[1] [Java 正则表达式详解]: https://segmentfault.com/a/1190000009162306
[2] [正则表达式(Java版整理)]: https://www.cnblogs.com/yw0219/p/8047938.html
[3] [正则表达式之 贪婪与非贪婪模式详解]: https://www.cnblogs.com/520yang/articles/7473596.html