正则表达式

正则表达式是强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作。String类里也提供了几个特殊的方法:

  • boolean matches(String regex):判断该字符串是否匹配指定的正则表达式。
  • String replaceAll(String regex, String replacement):将该字符串中所有匹配regex的子串替换成replacement。
  • String replaceFirst(String regex, String replacement):将该字符串中第一个匹配regex的子串替换成replacement。
  • String[] split(String regex):以regex作为分隔符,把该字符串分割成多个子串。

上面这些特殊的方法都依赖于Java提供的正则表达式支持,除此之外,Java还提供了Pattern和Matcher两个类专门用于提供正则表达式支持。

创建正则表达式

正则表达式就是用于匹配字符串的模板,可以匹配一批字符串,所以创建正则表达式就是创建一个特殊的字符串,由合法字符和特殊字符组成:
合法字符详细:

特殊字符详细:

将上面多个字符组合使用即可创建正则表达式:

"\\u0041\\"  //匹配a\
"\\0101\t"   //匹配a<制表符>
"\?\["   //匹配?[

上面的正则表达式依然只能匹配单个字符,这是因为还未在正则表达式中使用“通配符”,“通配符”可以匹配多个字符,这里我们将其称为预定于字符:

上面的7个预定义字符其实很容易记忆——d是digit的意思,代表数字;s是space的意思,代表空白;w是word的意思,代表单词。d、s、w的大写形式恰好匹配与之相反的字符。

有了预定义字符后,就可以更方便的创建正则表到式:

c\wt  //可以匹配cat、cbt、cct、c0t、c9t等一批字符串
\d\d\d-\d\d\d-\d\d\d\d  //匹配如000-000-0000形式的电话号码

在一些特殊情况下,例如,若想匹配a~f的字母,或者匹配除了ab之外的所有小写字母,或者匹配中文字符,这里我们可以使用方括号表达式:

正则表示还支持圆括号表达式,用于将多个表达式组成一个子表达式,圆括号中可以使用或运算符(|)。例如,正则表达式"(public|protected|private)"用于匹配Java的三个访问控制符其中之一。
正则还支持对头尾的匹配,使用边界匹配符:

正则表达式还提供了数量标识符,正则表达式支持的数量标识符有如下几种模式。

  • Greedy(贪婪模式):数量表示符默认采用贪婪模式,除非另有表示。贪婪模式的表达式会一直匹配下去,直到无法匹配为止。如果你发现表达式匹配的结果与预期的不符,很有可能是因为——你以为表达式只会匹配前面几个字符,而实际上它是贪婪模式,所以会一直匹配下去。
  • Reluctant(勉强模式):用问号后缀(?)表示,它只会匹配最少的字符。也称为最小匹配模式。
  • Possessive(占有模式):用加号后缀(+)表示,目前只有Java支持占有模式,通常比较少用
    三种模式数量表示符:

    关于贪婪模式和勉强模式的对比,看这个例子:
String str="hello , java!";
//贪婪模式的正则表达式
System.out.println(str.replaceFirst("\\w*" , "■"));       //输出■ , java!
//勉强模式的正则表达式
System.out.println(str.replaceFirst("\\w*?" , "■"));      //输出■hello , java!

正则表达式的使用

一旦在程序中定义了正则表达式,就可以使用Pattern和Matcher来使用正则表达式。
Pattern对象时正则表达式编译后的内存中的表示形式,因此,正则表达式字符串必须先被编译成为Pattern对象,然后在利用该Pattern对象创建对应的Matcher对象。执行匹配所涉及的状态保留在Matcher对象中,多个Matcher对象可共享同一个Pattern对象。
因此,典型的调用顺序如下:

import java.util.regex.Matcher;
import java.util.regex.Pattern;public class PatternTest {public static void main(String[] args){//将一个字符串编译成Pattern对象Pattern p=Pattern.compile("a*b");// 使用Pattern对象创建Matcher对象Matcher m=p.matcher("aaaaab");boolean b=m.matches(); //返回trueSystem.out.println(b);}
}

上面定义的Pattern对象可以多次重复使用。如果某个正则表达式仅需一次使用,则可直接使用Pattern类的静态matches方法,此方法自动把指定字符串编译成匿名的Pattern对象,并执行匹配,如下:

boolean b=Pattern.matches("a*b", "aaaaab");  //返回true

上面语句等效于前面的三条语句。但采用这种语句每次都需要重新编译新的Pattern对象,不能重复利用已编译的Pattern对象,所以效率不高。
Pattern是不可变类,可供多个并发线程安全使用。
Matcher类提供了如下几个常用方法。

  • find():返回目标字符串中是否包含与Pattern匹配的子串。
  • group():返回上一次与Pattern匹配的子串。
  • start():返回上一次与Pattern匹配的子串在目标字符串中的开始位置。
  • end():返回上一次与Pattern匹配的子串在目标字符串中的结束位置加1。
  • lookingAt():返回目标字符串前面部分与Pattern是否匹配。
  • matches():返回整个目标字符串与Pattern是否匹配。
  • reset(),将现有的Matcher对象应用于一个新的字符序列。

在Pattern、Matcher类的介绍中经常会看到一个CharSequence接口,该接口代表一个字符序列,其中CharBuffer、String、StringBuffer、StringBuilder都是它的实现类。简单地说,CharSequence代表一个各种表示形式的字符串。

通过Matcher类的find()和group()方法可以从目标字符串中依次取出特定子串(匹配正则表达式的子串),下面的例子程序示范了这种用途:

import java.util.regex.Matcher;
import java.util.regex.Pattern;public class FindGroup {public static void main(String[] args){//创建一个Pattern对象,并用它建立一个Matcher对象Matcher m= Pattern.compile("\\w+").matcher("Java is very easy!");while (m.find()){System.out.println(m.group());}int i=0;while (m.find(i)){System.out.println(m.group() + "\t");i++;}}
}

下面是运行结果:

Java
is
very
easy
Java    ava va  a   is  is  s   very    very    ery ry  y   easy    easy    asy sy  y

从上面运行结果可以看出,find()方法依次查找字符串中与Pattern匹配的子串,一旦找到对应的子串,下次调用find()方法时将接着向下查找。除此之外,find()方法还可以传入一个int类型的参数,带int参数的find()方法从该int索引处向下搜索。
start()和end()方法主要用于确定子串在目标字符串中的位置,如下程序所示:

import java.util.regex.*;public class StartEnd {public static void main(String[] args){//创建一个Pattern对象,并用它建立一个Matcher对象String regStr="Java is very easy!";System.out.println("目标字符串是:" + regStr);Matcher m=Pattern.compile("\\w+").matcher(regStr);while (m.find()){System.out.println(m.group()+"子串的其实位置:"+m.start()+",其结束位置:"+m.end());}}
}

matcher()和lookingAt()方法有点相似,只是matcher()方法要求整个字符串和Pattern完全匹配时才返回true,而lookingAt()只要字符串以Pattern开头就会返回true。reset()方法可将现有的Matcher对象应用于新的字符序列。看如下例子:

import java.util.regex.*;public class MatchesTest
{public static void main(String[] args){String[] mails={"kongyeeku@163.com" ,"kongyeeku@gmail.com","ligang@crazyit.org","wawa@abc.xx"};String mailRegEx="\\w{3,20}@\\w+\\.(com|org|cn|net|gov)";Pattern mailPattern=Pattern.compile(mailRegEx);Matcher matcher=null;for (String mail : mails){if (matcher==null){matcher=mailPattern.matcher(mail);}else{matcher.reset(mail);}String result=mail + (matcher.matches() ? "是" : "不是")+ "一个有效的邮件地址!";System.out.println(result);}}
}

上面程序创建了一个邮件地址的Pattern,接着用这个Pattern与多个邮件地址进行匹配。当程序中的Matcher为null时,程序调用matcher()方法来创建一个Matcher对象,一旦Matcher对象被创建,程序就调用Matcher的reset()方法将该Matcher应用于新的字符序列。
事实上,String类里也提供了matches()方法,该方法返回该字符串是否匹配指定的正则表达式。例如:

"kongyeeku@163.com".matches("\\w{3,20}@\\w+\\.(com|org|cn|net|gov)")
//返回true

除此之外,还可以利用正则表达式进行对目标字符串的分割、查找、替换等操作,看如下例子:

import java.util.regex.*;public class ReplaceTest {public static void main(String[] args){String[] msgs={"Java has regular expressions in 1.4","regular expressions now expressing in Java","Java represses oracular expressions"};Pattern p=Pattern.compile("re\\w*");Matcher matcher=null;for (int i=0 ; i < msgs.length ; i++){if (matcher==null){matcher=p.matcher(msgs[i]);}else{matcher.reset(msgs[i]);}System.out.println(matcher.replaceAll("哈哈:)"));System.out.println(matcher.replaceFirst("666"));}}
}

还可以用来查找,例如邮编等:

import java.util.regex.Matcher;
import java.util.regex.Pattern;public class FindZipCode {public static Pattern ZIP_CODE_PATTERN = Pattern.compile("(?<![0-9])[0-9]{6}(?![0-9])");public static void findZipCode(String text) {Matcher matcher = ZIP_CODE_PATTERN.matcher(text);while (matcher.find()) {System.out.println(matcher.group());}}public static void main(String[] args) {findZipCode("邮编 100013,电话18612345678");}
}

java实例练习

E-mail格式合法性验证与自动修改

如何检验输入的E-mail格式是否合法,这在表单中运用得非常多。我们可以使用正则表达式来实现这一功能,并将其中错误的字符删除以产生合格的E-mail格式。

1.

新建项目checkEmail,并在其中创建一个checkEmail.java文件。在该类的主方法中使用Mather语句调用Pattern类的matcher()方法生成一个Matcher对象m,最后通过m.appendReplacement()方法实现自动修改功:

package chechEmail;import java.util.regex.*;public class chechEmail {public static void main(String[] args){String str="apple:1973@164.com";Pattern p=Pattern.compile("^\\.|^\\@");  //检测输入的Email地址是否以非法符号"."或"@"开头Matcher m=p.matcher(str);if (m.find()){System.out.println("EMAIL地址不能以'.'或'@'作为起始字符");}p = Pattern.compile("^www\\.");        // 检测是否以“www.”为起始m = p.matcher(str);if (m.find()) {System.out.println("EMAIL地址不能以'www.'起始");}p = Pattern.compile("[^A-Za-z0-9\\.\\@_\\-~#]+");// 检测是否包含非法字符m = p.matcher(str);StringBuffer sb = new StringBuffer();boolean result = m.find();boolean deletedIllegalChars = false;while (result) {deletedIllegalChars = true;        // 如果找到了非法字符那么就设下标记// 如果里面包含非法字符如冒号双引号等,那么就把他们消去,加到SB里面m.appendReplacement(sb, "");result = m.find();} m.appendTail(sb);String str1 = sb.toString();if (deletedIllegalChars) {System.out.println("输入的EMAIL地址里包含有冒号、逗号等非法字符,请修改");System.out.println("您现在的输入为: " + str);System.out.println("修改后合法的地址应类似: " + str1);}}
}

《疯狂java讲义》学习(25):正则表达式相关推荐

  1. 疯狂JAVA讲义学习——基础代码练习——Interface——接口

    Java 接口 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承接口的抽象方法. 接口并 ...

  2. 《疯狂JAVA讲义》学习笔记(一)

    本人之前一直从事iOS开发,最近开始接触Eclipse插件开发,打算先重拾一下扔了很久的Java.看到大家都在网上推荐李刚的<疯狂JAVA讲义>,于是下了一本开始学习.以下为前七章本人记录 ...

  3. 《疯狂Java讲义》学习笔记 第六章 面向对象(下)

    <疯狂Java讲义>学习笔记 第六章 面向对象(下) 6.1包装类 基本数据类型 包装类 byte Byte short Short int Integer long Long char ...

  4. 学习《疯狂Java讲义第4版》PDF+代码+课件+面试题分析

    学习java选择了<疯狂java讲义>最新的第四版,用了两个多月时间看完,一边阅读,一边敲代码.对Java有了不少新的认识.书中实例清晰明了,讲解也是娓娓道来.Java可以编写图形桌面系统 ...

  5. 《疯狂Java讲义》学习笔记 第六章 面向对象(下续)

    这里## 6.6 Java 9改进的接口 6.6.1 接口的概念 6.6.2 Java 9中接口的定义 6.6.3接口的继承 ==以下代码中纯在自己的很多错误== 6.6.4使用接口 6.6.5接口和 ...

  6. 疯狂Python讲义学习笔记(含习题)之 常见模块

    一.sys模块 sys模块代表了Python解释器,主要用于获取和Python解释器相关的信息. >>> import sys >>> [e for e in di ...

  7. 疯狂python讲义学习笔记——中十章完结

    #第十一章 thinker import tkinter as tk print(help(tk.Button.__init__))#以按扭为例查看有什么属性 class myApplication( ...

  8. 疯狂Kotlin讲义学习笔记07章:面向对象(上)对象,中缀,解构,幕后字段、属性,延迟初始化,访问控制符,构造器,继承,重写,super限定,重写,多态,is类型检查,as强制类型转换

    1.定义类的标准格式 修饰符 class 类名 [ constructor 主构造器]{零到多个次构造器定义零到多个属性....零到多个方法.... } 修饰符open是final的反义词,用于修饰一 ...

  9. 疯狂java讲义第五章课后习题答案

    1.编写一个学生类,提供name.age.gender.phone.address.cmail成员变量,且为每个成员变量提供 seter.geter方法.为学生类提供默认的构造器和带所有成员变量的构造 ...

  10. 【社区图书馆】疯狂 Java 讲义:但凡种种,不一而足

    虽说酒香不怕巷子深,但是千里之外并不一定能闻到,有人看到这可能会感觉这不免有些杠的味道,其实我想表达的是好酒也需要宣传,比如今天我所要讲的这本书<疯狂Java讲义>. 这不是[赠书活动], ...

最新文章

  1. 关于Facebook iOS UI 工具ComponentKit简介
  2. 阿里云服务器1M带宽是多少
  3. [react] 你用过react版本有哪些?
  4. Netty实战项目:Spring boot 程序的聊天程序
  5. Android5.1自定义闹钟铃声,Android 设置来电铃声、通知铃声、闹钟铃声中的坑
  6. LeetCode(637)——二叉树的层平均值(JavaScript)
  7. 致敬HarmonyOS不平凡的2020,热情背后还有多少期待
  8. jQuery获取元素坐标
  9. 23种设计模式及案例整理分享(建议收藏)
  10. 分享一张牛逼的程序员职业路线图给你们!
  11. 22 模块:宏伟蓝图
  12. 【百度分享】javascript中函数调用过程中的this .
  13. SEO伪原创文章批量生成的方法「冷师兄」
  14. 《我在大学挺好的》之——选择了计算机专业
  15. 用html5画瀑布图,漂亮的Excel瀑布图,竟然如此简单~~
  16. python_计算一张纸对折多少次超过珠峰
  17. python语法简单吗_python基本语法练习实例 python好学吗? 语法简单吗? 举个例子?...
  18. 在Linux和Windows上安装kafka(版本:2.12-2.8.0)
  19. 62-Mybatis高级介绍
  20. 宽和窄俯卧撑哪个更难_窄距俯卧撑到底该多窄?

热门文章

  1. 智慧高速公路?重点如下
  2. Thoughtworks感受
  3. IBinder与Binder关系
  4. 聊天室 1.0 (TCP协议)客户端
  5. 年会弹幕文字_活动现场互动弹幕_教你大屏幕上的弹幕怎么做
  6. 每次开机无线网卡启动慢,无法连接无线网络,等一段时间恢复正常
  7. VB连接数据库时出现“ActiveX部件不能创建对象”
  8. 【tkinter扩展库】tkdev4
  9. 虚拟 sim 卡服务器,基于虚拟SIM卡的内置多虚拟SIM卡方法
  10. Python基础(三)列表、元组、字典、集合