正则表达式03

5.6正则表达式三个常用类

java.util.regex 包主要包括以下三个类:Pattern类、Matcher类和PatternSyntaxException类

  • Pattern类

    Pattern对象是一个正则表达式对象。Pattern类没有公共构造方法,要创建一个Pattern对象,调用其公共静态方法,它返回一个Pattern对象。该方法接收一个正则表达式作为它的第一个参数,比如:Pattern r = Pattern.compile(pattern);

  • Matcher类

    Matcher对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher类也没有公共构造方法。需要调用Pattern对象的matcher方法来获得一个Matcher对象

  • PatternSyntaxException类

    PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

5.6.1Pattern类

JAVA正则表达式, matcher.find()和 matcher.matches()的区别

  1. find()方法是部分匹配,是查找输入串中与模式匹配的子串,如果该匹配的串有组还可以使用group()函数
  2. matches()是全部匹配,是将整个输入串与模式匹配,如果要验证一个输入的数据是否为数字类型或其他类型,一般要用matches()
package li.regexp;

import java.util.regex.Pattern;

//演示matcher方法,用于整体匹配(注意是整个文本的匹配),在验证输入的字符串是否满足条件使用
public class PatternMethod {
public static void main(String[] args) {
String content="hello abc hello,侬好";
//String regStr="hello";//false
String regStr="hello.*";//true boolean matches = Pattern.matches(regStr, content);
System.out.println("整体匹配="+matches);
}
}

matches方法的底层源码:

public static boolean matches(String regex, CharSequence input) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
return m.matches();
}

可以看到,底层还是创建了一个正则表达式对象,以及使用matcher方法,最后调用matcher类的matches方法(该方法才是真正用来匹配的)

5.6.2Matcher类

package li.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern; //Matcher类的常用方法
public class MatcherMethod {
public static void main(String[] args) {
String content = "hello edu jack tom hello smith hello";
String reStr = "hello";
Pattern pattern = Pattern.compile(reStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("====================");
System.out.println(matcher.start());
System.out.println(matcher.end());
System.out.println("找到:" + content.substring(matcher.start(), matcher.end()));
} //整体匹配方法,常用于校验某个字符串是否满足某个规则
//Pattern的matches方法底层调用的就是Matcher类的matches方法
System.out.println("整体匹配=" + matcher.matches());//false content = "hello edu jack hspedutom hello smith hello hspedu hspedu";
//如果content有字符串 hspedu,就将其替换为 小猫咪
reStr = "hspedu";
pattern = Pattern.compile(reStr);
matcher = pattern.matcher(content);
//注意:返回的字符串newStringContent才是替换后的字符,原来的字符串content是不变化的
String newStringContent = matcher.replaceAll("小猫咪");
System.out.println("newStringContent= " + newStringContent);
System.out.println("content= " + content);
}
}

5.7反向引用

请看下面的问题:

给定一段文本,请找出所有四个数字连在一起的子串,并且这四个数字要满足:

  1. 第一位与第四位相同
  2. 第二位与第三位相同

在解决前面的问题之前,我们需要了解正则表达式的几个概念:

  1. 分组

    我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看作是一个子表达式/分组

  2. 捕获

    把正则表达式中的 子表达式/分组 匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0代表的是整个正则式

    -详见5.4.6

  3. 反向引用

    圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用使用\\分组号,外部反向引用使用$分组号

5.7.1反向引用的匹配原理

捕获组(Expression)在匹配成功时,会将子表达式匹配到的内容,保存到内存中一个以数字编号的组里,可以简单的认为是对一个局部变量进行了赋值,这时就可以通过反向引用方式,引用这个局部变量的值。一个捕获组(Expression)在匹配成功之前,它的内容可以是不确定的,一旦匹配成功,它的内容就确定了,反向引用的内容也就是确定的了。

反向引用必然要与捕获组一同使用的,如果没有捕获组,而使用了反向引用的语法,不同语言的处理方式不一致,有的语言会抛异常,有的语言会当作普通的转义处理。

  • 看几个小案例

    1. 要匹配两个连续的相同数字 (\\d)\\1
    2. 要匹配五个连续的相同数字 (\\d)\\1{4}
    3. 要匹配个位与千位相同,十位与百位相同的数 (\\d) (\\d)\\2\\1
    4. 在字符串中检索商品编号,形式如:12321-333999111这样的号码,要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同

例子:

package li.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern; //反向引用
public class RegExp12 {
public static void main(String[] args) {
String content = "ke7887k5225e he12341551l12321-333999111lo ja11ck yy22y xx33333x";
//1. 要匹配两个连续的相同数字 (\\d)\\1
//String regStr="(\\d)\\1";
//2. 要匹配五个连续的相同数字 (\\d)\\1{4}
//String regStr="(\\d)\\1{4}";
//3. 要匹配个位与千位相同,十位与百位相同的数 (\\d)(\\d)\\2\\1
//String regStr="(\\d)(\\d)\\2\\1";
//在字符串中检索商品编号,形式如:12321-333999111这样的号码,
// 要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同
String regStr="\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
System.out.println("找到:"+matcher.group(0));
}
}
}

5.7.2去重

经典的结巴程序

把类似 “我.....我我要......学学学学.......编程java!”

这样一句话,通过正则表达式将其修改成“我要学编程java!”

package li.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern; //去重
public class RegExp13 {
public static void main(String[] args) {
String content = "我.....我我要......学学学学.......编程java!";
//1.去掉所有的 .
Pattern pattern = Pattern.compile("\\.");
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll("");//用空串替换掉.
System.out.println("去掉所有的\".\"=" + content); //2.去掉重复的字
//思路:
//2.1使用(.)\\1+去匹配连续重复的字
//2.2使用反向引用$1来替换匹配到的内容 //--注意:这里的正则表达式匹配的是多个重复的字,但是捕获的内容是重复的字中的一个,即圆括号
pattern = Pattern.compile("(.)\\1+");//分组的捕获内容记录到$1中
matcher = pattern.matcher(content);//因为正则表达式改变了,需要重置 matcher
while (matcher.find()) {
System.out.println("找到=" + matcher.group(0));
}
//使用反向引用$1来替换匹配到的内容
//注意:虽然上面的正则表达式是匹配到的连续重复的字,但是捕获的是圆括号里面的内容,所以捕获的组里面的字只有一个,
//因此使用replaceAll("$1")的意思是:用捕获到的单个字去替换匹配到的多个重复的字
content = matcher.replaceAll("$1");
System.out.println("去掉重复的字=" + content); //2.相当于:
// content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");
// System.out.println(content);
}
}

5.8替换分割匹配

5.8.1替换

使用正则表达式替换字符串可以直接调用 public String replaceAll(String regex,String replacement) ,它的第一个参数是正则表达式,第二个参数是要替换的字符串。

给出一段文本:

/*
2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日,J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升。
*/

将这段文字中的 JDK1.3 JDK1.4 统一替换成 JDK

package li.regexp;

//替换
public class RegExp14 {
public static void main(String[] args) {
String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了" +
"Apple公司Mac OS X的工业标准的支持。2001年9月24日,J2EE1.3发布。2002" +
"年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升。"; //使用正则表达式,将JDK1.3/JDK1.4 统一替换成 JDK
content = content.replaceAll("JDK1.[34]", "JDK");
System.out.println(content);
}
}

5.8.3判断

String类 public boolean matches(String regex)

验证一个手机号码,要求必须是以138、139开头的

package li.regexp;

//匹配
public class RegExp14 {
public static void main(String[] args) {
//验证一个手机号码,要求必须是以138、139开头的十一位数字
String content="13899988880";
if (content.matches("13[89]\\d{8}")) {//matches是整体匹配,不用加定位符
System.out.println("验证成功");
}else {
System.out.println("验证失败");
}
}
}

5.8.3分割

String类 public String[] split(String regex)

例子

有如下字符串,要求按照#或者-或者~或者数字来分割

“hello#abc-jack12smith~北京”

package li.regexp;

//分割
public class RegExp14 {
public static void main(String[] args) { //要求按照# 或者- 或者~ 或者数字 来分割
String content = "hello#abc-jack12smith~北京";
String[] split = content.split("#|-|~|\\d+");
for (int i = 0; i < split.length; i++) {
System.out.println(split[i]);
}
}
}

5.9本章习题

5.9.1验证电子邮件格式

规定电子邮件格式为:

  1. 只能有一个@
  2. @前面是用户名,可以是a-z A-Z 0-9_-字符
  3. @后面是域名,并且域名只能是英文字母,比如 shouhu.com 或者 tsinghua.org.cn
  4. 写出对应的正则表达式,验证输入的字符串是否满足规则
package li.regexp;

public class Homework01 {
public static void main(String[] args) {
String content = "olien@tsinghua.org.cn";
//因此,String 的 marches方法是整体匹配,不用加定位符,但是建议加上
if (content.matches("^[\\w-]+@([a-zA-z]+\\.)+[a-zA-z]+$")) {
System.out.println("匹配成功");
} else {
System.out.println("匹配失败");
}
}
}

源码分析:

  1. 点击matches方法,可以看到String的marches方法:
public boolean matches(String regex) {
return Pattern.matches(regex, this);
}
  1. 再点击return的Pattern.matches方法:
public static boolean matches(String regex, CharSequence input) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
return m.matches();
}
  1. m.matches()方法:
/**
* Attempts to match the entire region against the pattern.-尝试将整个区域与模式匹配
*/
public boolean matches() {
return match(from, ENDANCHOR);
}

因此,String 的 marches方法是整体匹配,不用加定位符,但是建议加上

5.9.2验证整数或者小数

要求验证是不是整数或者小数

提示:这个题要考虑整数和负数

比如:123,-345,34.89,-87.0,-0.01,0.45等

package li.regexp;

public class Homework02 {
public static void main(String[] args) {
//要求验证是不是整数或者小数
//提示:这个题要考虑整数和负数
//比如:123,-345,34.89,-87.0,-0.01,0.45等
/**
* 思路:
* 1.先写出简单的正则表达式
* 2.再根据各种情况逐步地完善
* 2.1 [-+]? 考虑的是符号
* 2.2 小数点以及小数点后面的数字可以用 (\\.\\d+)?
* 2.3 小数点前面的应该存在数字,且分为两种情况:
* 2.3.1情况一:第一个应该以1-9开头,剩下的可能有0到多个数字, ([1-9]\\d*)
* 2.3.2情况二:小数点前面只有一位数字 0
* 两种情况整合起来就是 ([1-9]\\d*|0)
*/
String content = "-09.9";
//"^[-+]?([1-9]\\d*|0)(\\.\\d+)?$"
if (content.matches("^[-+]?([1-9]\\d*|0)(\\.\\d+)?$")) {
System.out.println("验证成功-是整数或者小数");
} else {
System.out.println("验证失败-不是整数或者小数");
}
}
}

5.9.3解析URL

对一个url进行解析 http://www.shhu.com:8080/abc/index.htm

  1. 要求得到协议是什么 http
  2. 域名是什么 www.shhu.com
  3. 端口是什么 8080
  4. 文件名是什么 index.htm

思路:分组,4组,分别获取到对应的值

package li.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern; public class Homework03 {
public static void main(String[] args) {
String content = "http://www.shhu.com:8080/abc/de/fgh/index.htm";
//如果名称中要求有特殊符号,就将特殊符号加入到中括号中
String regStr = "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.]+)$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if (matcher.matches()) {//整体匹配,如果匹配成功,可以通过group(x),获取对应分组的内容
System.out.println("整体匹配=" + matcher.group(0));
System.out.println("协议=" + matcher.group(1));
System.out.println("域名=" + matcher.group(2));
System.out.println("端口=" + matcher.group(3));
System.out.println("文件名=" + matcher.group(4));
} else {
System.out.println("没有匹配成功");
}
}
}

day52-正则表达式03的更多相关文章

  1. day5-2正则表达式

    正则表达式: 正则表达式对象的创建 1,构造函数 var pattern =new RegExp("正则表达式","修饰符") var pattern =new ...

  2. jQuery1.6源码分析系列

    原文地址:http://www.cnblogs.com/nuysoft/archive/2011/11/14/2248023.html jQuery源码分析(版本1.6.1) 目录 00 前言开光 0 ...

  3. jQuery1.6.1源码分析系列(作者:nuysoft/高云)

    作者:nuysoft/高云 QQ:47214707 Email:nuysoft@gmail.com jQuery源码分析(版本1.6.1) 00 前言开光 01 总体架构 02 正则表达式-RegEx ...

  4. JsonResponse类的使用、form表单上传文件补充、CBV和FBV、HTML的模板语法之传值与过滤器

    昨日内容回顾 Django请求生命周期 # 1.浏览器发起请求 到达Django的socket服务端(web服务网关接口) 01 wsgiref 02 uwsgi + nginx 03 WSGI协议 ...

  5. 03标准对象-02-RegExp 正则表达式

    1.基本概念 和 定义 用一种描述性的语言来给字符串定义一个规则,你可以形象地理解正则表达式是一个"框",凡是符合大小形状条件的字符串,都算是"匹配"了. JS ...

  6. javascript高级编程笔记03(正则表达式)

    引用类型 检测数组 注:我们实际开发中经常遇到要把数组转化成以逗号隔开,我以前都是join来实现,其实又更简单的方法可以用toString方法,它会自动用逗号隔开转换成字符串,其实toString内部 ...

  7. Linux07--Shell程序设计03 通配符与正则表达式

    通配符 通配符可用于代替字符. 通常地,星号“*”匹配0个或以上的字符,问号“?”匹配1个字符. 使用情况: 1.文件和目录 在CP/M.DOS.Microsoft Windows和类Unix操作系统 ...

  8. day52 Pyhton 前端03

    内容回顾 块级标签: div p h 列表:ol;ul;dl 表格:table 行内标签: span a i/em b/strong u/del 行内块: input textarea img 其他: ...

  9. JS正则表达式常用总结

    正则表达式的创建 JS正则表达式的创建有两种方式: new RegExp() 和 直接字面量. //使用RegExp对象创建 var regObj = new RegExp("(^\\s+) ...

随机推荐

  1. 美女 Committer 手把手教你部署 Apache DolphinScheduler 单机版

    还在为如何部署Apache DolphinScheduler 发愁么?自上篇<美女 Committer 手把手教你使用海豚调度>的视频发布后,受到社区伙伴们的热烈欢迎.但个别小伙伴在部署这 ...

  2. java学习第六天集合框架.day15

    Set接口 Set集合存储特点: 不允许元素重复 不会记录元素的添加先后顺序 Set只包含从Collection继承的方法,不过Set无法记住添加的顺序,不允许包含重复的元素.当试图添加两个相同元素进 ...

  3. 创建Prism项目

    1.创建Prism Prism是一个用于WPF.Xamarin Form.Uno平台和 WinUI 中构建松散耦合.可维护和可测试的XAML应用程序框架 通过以下方式访问.使用.学习它: https: ...

  4. java数组---数组的使用(打印,求和,最大值)

    public static void main(String[] args) { int[] arrays={1,2,3,4,5}; //打印该数组 for (int i = 0; i < ar ...

  5. Linux安装Jenkins及配置svn使用

    目录 1. 下载 2. 创建文件夹 3. 安装 4. 修改端口,不用这步 5. 安装插件提速 6. 启动 7. 页面访问 8. 新建用户 9. 安装Subversion插件 10. 安装maven插件 ...

  6. token总结

    token 总结 1. token 和SessionID 的区别 Token机制相对于Cookie机制又有什么好处呢? 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的 ...

  7. 【Android 逆向】手动构造dex文件

    public class Hello { public static void main(String[] args) { System.out.println("hello android ...

  8. Object.keys的‘诡异’特性,你值得收藏!

    先从'诡异'的问题入手 例1: 纯Number类型的属性 const obj = { 1: 1, 6: 6, 3: 3, 2: 2 } console.log('keys', Object.keys( ...

  9. openresty(nginx) 配置 stream 转发

    nginx从1.9.0开始,新增加了一个stream模块,用来实现四层协议的转发.代理或者负载均衡等. (1)关于stream域的模块有哪些? 目前官网上列出的第三方模块.简直就是http模块的镜像. ...

  10. rook-ceph说明

    cluster.yaml文件 文件中有几个地方要注意: dataDirHostPath: 这个路径是会在宿主机上生成的,保存的是ceph的相关的配置文件,再重新生成集群的时候要确保这个目录为空,否则m ...