正则表达式的子表达式(分组)不是很好懂,但却是很强大的文本处理工具。

1 正则表达式热身

匹配电话号码
// 电话号码匹配
// 手机号段只有 13xxx 15xxx 18xxxx 17xxx
System.out.println("18304072984".matches("1[3578]\\d{9}"));   // true// 座机号:010-65784236,0316-3312617,022-12465647,03123312336
String regex = "0\\d{2}-?\\d{8}|0\\d{3}-?\\d{7}";
String telStr = "010-43367458";
System.out.println(telStr.matches(regex));  // true
匹配邮箱
String mail = "i@jiaobuchong.com.cn";
String reg = "[a-zA-Z_0-9]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,2}";
System.out.println(mail.matches(reg));  // true
特殊字符替换

将不是中文的字符替换为空:

String input = "神探狄仁&*%$杰之四大天王@bdfbdbdfdgds23532";
String reg = "[^\\u4e00-\\u9fa5]";
input = input.replaceAll(reg, "");
System.out.println(input);   // 神探狄仁杰之四大天王

汉字的Unicode编码范围是:\u4e00-\u9fa5

2 分组

组是用括号划分的正则表达式,可以根据组的编号来引用某个组。组号为 0 表示整个表达式,组号 1 表示第一对括号扩起的组,以此类推。
看 Java API 中 Pattern 中的描述:
Capturing groups are numbered by counting their opening parentheses from left to right. In the expression ((A)(B(C))), for example, there are four such groups:

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

再比如 A(B(C))D 有三个组:组 0 是 ABCD,组 1 是 BC,组 2 是 C,
可以根据有多少个左括号来来确定有多少个分组,括号里的表达式都称子表达式。

Eg1:

Matcher 对象提供很多方法:

  1. goupCount() 返回该正则表达式模式中的分组数目,对应于「左括号」的数目
  2. group(int i) 返回对应组的匹配字符,没有匹配到则返回 null
  3. start(int group) 返回对应组的匹配字符的起始索引
  4. end(int group) 返回对应组的匹配字符的最后一个字符索引加一的值
// 这个正则表达式有两个组,
// group(0) 是 \\$\\{([^{}]+?)\\}
// group(1) 是 ([^{}]+?)
String regex = "\\$\\{([^{}]+?)\\}";
Pattern pattern = Pattern.compile(regex);
String input = "${name}-babalala-${age}-${address}";Matcher matcher = pattern.matcher(input);
System.out.println(matcher.groupCount());
// find() 像迭代器那样向前遍历输入字符串
while (matcher.find()) {System.out.println(matcher.group(0) + ", pos: "+ matcher.start() + "-" + (matcher.end() - 1));System.out.println(matcher.group(1) + ", pos: " +matcher.start(1) + "-" + (matcher.end(1) - 1));
}

输出:

1
${name}, pos: 0-6
name, pos: 2-5
${age}, pos: 17-22
age, pos: 19-21
${address}, pos: 24-33
address, pos: 26-32

group,翻译成中文就是分组。
group()group(0)对应于整个正则表达式每次匹配到的内容,
group(1)表示括号中(一个子表达式分组)匹配到的内容。

Eg2:

为了更直观的看分组,在 Eg1 的正则表达式上再多加一对括号:

String regex = "(\\$\\{([^{}]+?)\\})";
Pattern pattern = Pattern.compile(regex);
String input = "${name}-babalala-${age}-${address}";Matcher matcher = pattern.matcher(input);
// matcher.find() 方法会对 input 这个字符串多次进行匹配,如果能匹配到,这个匹配结果里就会包含多个分组,我们可以从分组里提取我们想要的结果
while (matcher.find()) {System.out.println(matcher.group(0) + ", pos: " + matcher.start());System.out.println(matcher.group(1) + ", pos: " + matcher.start(1));System.out.println(matcher.group(2) + ", pos: " + matcher.start(2));
}

输出:

${name}, pos: 0
${name}, pos: 0
name, pos: 2
${age}, pos: 17
${age}, pos: 17
age, pos: 19
${address}, pos: 24
${address}, pos: 24
address, pos: 26

由此可得出一对括号一个分组,可以通过左括号数来确定有多少个分组。

通过group()获取分组中的匹配字串应用场景很广泛,
在笔者的一个项目中,通过使用这个特性实现了很有意思的通配符替换,感动!

Eg3(通过分组提取想要的数据):
        // 这个正则表达式会提取字符串中的「数字」和「字母」Pattern pattern = Pattern.compile("([0-9]+).*?([a-zA-Z]+)");String input = "那就20200719这样吧sunny。。。。。。。122432该拿什么与眼泪抗衡twinkle";Matcher matcher = pattern.matcher(input);// 每个匹配到的子串分组的个数int group = matcher.groupCount();// 如果输入串有多个可被匹配的子串,这里会多次进行匹配while (matcher.find()) {System.out.println("匹配到的子串:" + matcher.group());  // 匹配到的子串for (int i = 1; i <= group; i++) {System.out.println("分组" + i + ": " + matcher.group(i));}}

输出:

匹配到的子串:20200719这样吧sunny
分组1: 20200719
分组2: sunny
匹配到的子串:122432该拿什么与眼泪抗衡twinkle
分组1: 122432
分组2: twinkle

3 分组替换

Eg1:
String tel = "18304072984";
// 括号表示组,被替换的部分$n表示第n组的内容
tel = tel.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
System.out.print(tel);   // output: 183****2984

replaceAll 是一个替换字符串的方法,正则表达式中括号表示一个分组,replaceAll 的参数 2 中可以使用 $n(n 为数字)来依次引用子表达式中匹配到的分组字串,"(\\d{3})\\d{4}(\\d{4})", "$1****$2",分为前(前三个数字)中间四个数字(最后四个数字) 替换为(第一组数字保持不变 $1)(中间为 * )(第二组数字保持不变 $2)

Eg2:
String one = "hello girl hi hot".replaceFirst("(\\w+)\\s+(\\w+)", "$2 $1");
String two = "hello girl hi hot".replaceAll("(\\w+)\\s+(\\w+)", "$2 $1");
System.out.println(one);   // girl hello hi hot
System.out.println(two);   // girl hello hot hi

理解了Eg1,这个例子也自然就理解了。

Eg3:

来一个实用的例子,重复标点符号替换:

String input = "假如生活欺骗了你,,,相信吧,,,快乐的日子将会来临!!!…………";// 重复标点符号替换
String duplicateSymbolReg = "([。?!?!,]|\\.\\.\\.|……)+";
input = input.replaceAll(duplicateSymbolReg, "$1");
System.out.println(input);

输出:

假如生活欺骗了你,相信吧,快乐的日子将会来临!……

正则表达式:([。?!?!,]|\\.\\.\\.|……)+,括号中是一个分组:表示一个标点符号,+表示这个分组出现一次或多次,$1分组的内容(一个标点符号)。replaceAll 就使用$1去对字符串进行替换了。

Eg4:

IP地址排序

String ip = "192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30";
ip = ip.replaceAll("(\\d+)", "00$1");
System.out.println(ip);ip = ip.replaceAll("0*(\\d{3})", "$1");
System.out.println(ip);
String[] strs = ip.split(" ");Arrays.sort(strs);
for (String str : strs) {str = str.replaceAll("0*(\\d+)", "$1");System.out.println(str);
}

输出:

00192.0068.001.00254 00102.0049.0023.00013 0010.0010.0010.0010 002.002.002.002 008.00109.0090.0030
192.068.001.254 102.049.023.013 010.010.010.010 002.002.002.002 008.109.090.030
2.2.2.2
8.109.90.30
10.10.10.10
102.49.23.13
192.68.1.254
  1. 让IP地址的每一段都是3位,替换之后有4位的情况
  2. 保证IP地址每一段都是3位
  3. 排序之

写到这里,笔者不禁感叹,真的很强大!

4 反向引用

使用小括号指定一个子表达式分组后,匹配这个子表达式的文本可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:以分组的左括号为标志,从左向右,第一个分组的组号为1,第二个为2,以此类推。

Eg:
/* 这个正则表达式表示 安安静静 这样的叠词 */
String regex = "(.)\\1(.)\\2";
System.out.println("安安静静".matches(regex));   // true
System.out.println("安静安静".matches(regex));   // false

上面 (.) 表示一个分组,里面 . 表示任意字符,每一个字符都是一个分组,
\\1表示组1()又出现了一次,\\2表示组2()又出现了一次。

那匹配 安静安静,怎么写正则表达式?根据上面的例子,将安静分成一个组,然后这个组又出现了一次就是安静安静

String regex = "(..)\\1";
System.out.println("安静安静".matches(regex));   // true
System.out.println("安安静静".matches(regex));   // false

5 反向引用替换

Eg1:
String str = "我我...我我...我要..要要...要要...找找找一个....女女女女...朋朋朋朋朋朋...友友友友友..友.友...友...友友!!!";/*将 . 去掉*/
str = str.replaceAll("\\.+", "");
System.out.println(str);str = str.replaceAll("(.)\\1+", "$1");
System.out.println(str);

输出:

我我我我我要要要要要找找找一个女女女女朋朋朋朋朋朋友友友友友友友友友友!!!
我要找一个女朋友!

(.)表示任意一个字符都会成为一个分组;\\1+ 引用分组(一个字符),表示出现1次或多次这个分组。 $1引用分组(.)将多个重复字符替换成一个字符。

Eg2:

替换重复出现的两位数之间的内容:

"xx12abdd12345".replaceAll("(\\d{2}).+?\\1", "");  //结果为 xx345

是不是觉得很神奇!

使用replace系列的方法要注意的一个异常: Java replaceAll()方法报错Illegal group reference
参考:
Java正则篇-27-正则的替换和分组功能
正则表达式30分钟入门教程
正则基础之——捕获组(capture group)
Java正则表达式Pattern与Matcher类
Java学习之正则表达式
Java进阶——使用正则表达式检索、替换String中的特定字符和关于正则表达式的一切
java 去除空格、标点符号

Java正则表达式之分组和替换相关推荐

  1. java正则表达式 匹配()_学习Java正则表达式(匹配、替换、查找)

    import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; public c ...

  2. 【Java正则表达式】正则基本语法、使用方式(分组、替换、分割)、简单爬虫基础

    正则表达式基本语法 笔记扫描版 在Java中使用正则表达式 示例1:一个简单的正则表达式 package cn.hanquan.reg;import java.util.regex.Matcher; ...

  3. 用JAVA正则表达式轻松替换JSON中大字段

    用JAVA正则表达式轻松替换JSON中大字段 (一)背景 (二)正则表达式 (三)在JAVA代码中的实现 (四)合并正则表达式 (五)最终结果 (六)所感 (一)背景 在软件开发工作中我们经常用JSO ...

  4. java正则表达式 替换标签内容_使用Java正则表达式替换HTML标签

    一.实现目标 实现多个个HTML页的合并预览,需要如下处理 1)去掉meta标签 2)替换input标签,只保留value值(因为是预览,不保留输入框) 3)移除隐藏的input标签,即type=&q ...

  5. java正则表达式 替换空格_Java正则表达式替换移除空行和多余的空格

    这几天重拾Java写代码,须要操做文本文件中的内容.正则表达式 最终,要把内容里的空行和多余的连续空格移除,使用String里的replace或者replaceAll,试了不少次都没有成功.spa 最 ...

  6. java正则表达式替换特殊字符_使用正则表达式替换报表名称中的特殊字符(推荐)...

    正则表达式,又称规则表达式.(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念.正则表通常被用来检索.替换那些符合某个模式(规则)的文 ...

  7. bigint对应java什么类型_「JAVA」从格式化输出到扫描输入,深究Java正则表达式匹配之道

    字符串是不可变的 字符串是不可变的,也就是说当字符串的内容发生改变的时候,会创建一个新的String对象:但是如果内容没有发生改变的时候,String类的方法会返回原字符串对象的引用. 而正则表达式往 ...

  8. JAVA正则表达式:Pattern类与Matcher类详解(转)

    java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包.它包括两个类:Pattern和Matcher Pattern 一个Pattern是一个正则表达式经编译后的表 ...

  9. 一起来看看java正则表达式

    首先是字符解释: 字符 描述 \ 将下一个字符标记为一个特殊字符.或一个原义字符.或一个 向后引用.或一个八进制转义符.例如,'n' 匹配字符 "n".'\n' 匹配一个换行符.序 ...

最新文章

  1. java大作业私人管家系统_操作系统概念(Operating System Concepts)第十版期中大作业...
  2. Google发布机器学习术语表 (中英对照)
  3. 资源 | 25个深度学习开源数据集,have fun !
  4. 圆形和多边形雷达图python-Matplotlib绘制雷达图和三维图的示例代码
  5. python中有没有switch_Python为什么没有switch/case语句?
  6. JavaScript教程--从入门到精通
  7. socket通信数据类型
  8. Python-学生信息管理系统.exe(代码)
  9. 雷鸟html签名设置,thunderbird 使用OpenPGP加解密邮件
  10. java 弹出软键盘_Android开发之弹出软键盘工具类简单示例
  11. 解决java compiler level does not match the version of the inst
  12. 【ElasticSearch】ElasticSearch 节点 性能 健康 监控
  13. visual studio哪一款比较好用_电脑桌面上使用的工作便签软件下载哪一款好用?...
  14. 百度SEO之-关键词的种类
  15. 利润表模板excel_Excel教程:作为财务,这些excel技巧你还不会吗?
  16. 计算机操作系统(汤小丹)慕课版课后题答案第五章:储存器管理
  17. opencl icd---OpenCL Installable Client Driver (ICD) Loader
  18. ubuntu-UML画图工具 Virtual_Paradigm
  19. python基于django的校园公寓宿舍报修管理系统设计与实现
  20. Studio 3T for MongoDB

热门文章

  1. matlab bwmorph spur,matlab图像处理学习笔记-数学形态与二值图像操作
  2. 从小米上市了解CDR和“同股不同权”
  3. 分享UCI两个可用于预测的数据集Diabetes和Heart Disease
  4. python编程基础人邮版答案_《Python Web 编程》(人邮出版社)作业答案下载
  5. 外媒:谷歌称继续推动华为禁令可能带来美国国家安全风险
  6. Java——this关键字(调用本类属性、调用本类方法、表示当前对象)
  7. 就这样,我走完了程序员的前五年,共勉!
  8. Python爬取新浪新闻评论的url查找方法
  9. 图像加权和制作鬼影---OpenCV-Python开发指南(2)
  10. 转载:KOF97坂琦良心得