Java正则表达式的总结
Java正则表达式,可以用于很多类型的文本处理, 如匹配,搜索,提取和分析结构化内容.
判断用户的输入是否符合实际需求。
本文将对java正则表达式做总结。
大部分人会觉得java正则表达式是很复杂的,本文由简入深的介绍java正则表达式。
如果你是想简单的了解,看前面的内容就可以了。
如果想深入理解一下,可以多看一点。
一.简单的正则表达式
(一)几个简单示例展示:
package com.xykj.matcher;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
/**
* 正则表达式其实也是一串字符串
* 先说几个简单的符号意义
* 1.[]的使用,里面可以放多个字符,代表任选其中一个
* 2.\\d代表任意数字
* 3.{N}代表前面的东西可以出现N次
* */
public static void main(String[] args) {
//示例一: 判断输入的号码是不是身份证号码
//身份证16或18位 ,第一位不能是零,最后一位可以是Xx
//String的matches方法能支持正则表达式
String num="11234567891234561x";//定义身份证号码
String regex1="[1-9][\\d]{14}[\\dXx]";//判断十六位的正则表达式
String regex2="[1-9][\\d]{14}[\\dXx]";//判断十八位的正则表达式
//判断输入的字符串是否是符合要求,matches的使用
if (num.matches(regex1)||num.matches(regex2)) {
System.out.println("身份证号码匹配成功");
}else {
System.out.println("不是身份证号码");
}
//示例二: 去掉一个算式的加减乘除符号
//方法split(分割字符串)也支持正则表达式
String num2="12+3-8/5*7"; //算式
String regex3="[\\+\\*\\/-]"; //加减乘除的正则表达式,\\代表转义符,后面解释
String[] arr=num2.split(regex3); //使用正则表达式分割字符串
System.out.println(Arrays.toString(arr)); //打印数组的结果
//其实前面一题最简单的做法是:使用replaceAll
//把字符串中符合正则表达式的字符串用replaceAll方法的第二个参数代替
String a=num2.replaceAll(regex3, " ");
System.out.println(a);
}
}
上面的程序,涉及到了简答的正则表达式,其实就是String类里面的几个方法的使用。
(二)一个复杂一点的例子
里面的知识,在下面会有介绍
package com.xykj.matcher;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test2 {
/**
* 获得一长串字符串中的某些字符
*
* */
public static void main(String[] args) {
//比如从一长串字符串中获取电话号码
String str="我想购买一本《java疯狂讲义》,请尽快联系我13500006666"
+ "如果想交朋友,联系我13611125565"
+ "出售二手联想电脑,型号:5560,需要的人可以联系我15012354687";
//创建一个Pattern对象,并用在它建立一个Matcher对象
//假设手机号格式都是13X和15X,只有11位,实际设计中可以自己修改
String regex="((13)|(15))\\d{9}";
Matcher matcher=Pattern.compile(regex).matcher(str);//匹配元素
while (matcher.find()) {
System.out.println(matcher.group());//打印符合条件的字符串
}
}
}
结果会把:这三个号码都打印出来
运行结果:
13500006666
13611125565
15012354687
二.正则表达式的相关类和方法
java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。
它包括两个类: Pattern(模式)和Matcher(状态).
(一)Pattern
Pattern是一个正则表达式经编译后的表现模式。
在java中,通过适当命名的Pattern类可以容易确定String是否匹配某种模式.
模式可以象匹配某个特定的String那样简单,也可以很复 杂,需要采用分组和字符类,如空白,数字,字母或控制符.
因为Java字符串基于统一字符编码(Unicode),正则表达式也适用于国际化的应用程序.
Pattern类的方法简述
方法 | 说明 |
static Pettern compile(String regex,int flag) | 编译模式,参数regex表示输入的正则表达式,flag表示模式类型(Pattern.CASE_INSENSITIVE 表示不区分大小写) |
Matcher match(CharSequence input) | 获取匹配器,input时输入的待处理的字符串 |
static boolean matches(String regex, CharSequence input) | 快速的匹配调用,直接根据输入的模式regex匹配input |
String[] split(CharSequence input,int limit) | 分隔字符串input,limit参数可以限制分隔的次数 |
(二)Matcher
Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符串展开匹配检查。
首先一个Pattern实例订制了一个所用语法与 PERL的类似的正则表达式经编译后的模式,
然后一个Matcher实例在这个给定的Pattern实例的模式控制下进行字符串的匹配工作。
Matcher类的方法简述
方法 | 说明 |
boolean matches() | 对整个输入字符串进行模式匹配. |
boolean lookingAt() | 从输入字符串的开始处进行模式匹配 |
boolean find(int start) | 从start处开始匹配模式 |
int groupCount() | 返回匹配后的分组数目 |
String replaceAll(String replacement) | 用给定的replacement全部替代匹配的部分 |
String repalceFirst(String replacement) | 用给定的replacement替代第一次匹配的部分 |
Matcher appendReplacement(StringBuffer sb,String replacement) | 根据模式用replacement替换相应内容,并将匹配的结果添加到sb当前位置之后 |
StringBuffer appendTail(StringBuffer sb) | 将输入序列中匹配之后的末尾字串添加到sb当前位置之后. |
三.正则表达式中常见通配符
对于单字符串比较而言,使用正则表达式没有什么优势.
Regex的真正强大之处在于体现在包括字符类和量词(*,+,?)的更复杂的模式上.
(一)字符类代表的意义:
\d 数字
\D 非数字
\w 单字字符(0-9,A-Z,a-z)
\W 非单字字符
\s 空白(空格符,换行符,回车符,制表符)
\S 非空白
[] 由方括号内的一个字符列表创建的自定义字符类
. 匹配任何单个字符
下面的字符将用于控制将一个子模式应用到匹配次数的过程.
? 重复前面的子模式0次到一次
* 重复前面的子模式0次或多次
+ 重复前面的子模式一次到多次
(二)实例部分:
1.实例一: 对整个字符串的检验
要求:判断模式与要匹配的文本是不是等价的.
分析:静态的Pattern.matches方法用于比较一个String是否匹配一个给定模式.
代码如下:
String data="java";
String regex=”java”;
boolean result=Pattern.matches(regex,data);
2.实例二: +?*的用法
要求:判断一串字符串数组里面符合条件的字符串
代码如下:
String[] dataArr = { "moon", "mon", "moon", "mono" }; //要判断的数组
for (String str : dataArr) { //遍历每一个字符串
String patternStr="m(o+)n"; //正则表达式
boolean result = Pattern.matches(patternStr, str); //判断是否匹配
if (result) {
System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
}
else{
System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
}
}
模式是”m(o+)n”,它表示mn中间的o可以重复一次或多次,因此moon,mon,mooon能匹配成功,
而mono在n后多了一个o,和模式匹配不上.
注: +表示一次或多次;?表示0次或一次;*表示0次或多次.
3.实例三: [ ]的用法
要求:判断一串字符串数组里面符合条件的字符串
代码如下:
String[] dataArr = { "ban", "ben", "bin", "bon" ,"bun","byn","baen"};
for (String str : dataArr) {
String patternStr="b[aeiou]n";
boolean result = Pattern.matches(patternStr, str);
if (result) {
System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
}
else{
System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
}
}
注:方括号中只允许的单个字符,模式“b[aeiou]n”指定,只有以b开头,n结尾,中间是a,e,i,o,u中任意一个的才能匹配上,所以数组的前五个可以匹配,后两个元素无法匹配.
方括号[]表示只有其中指定的字符才能匹配.
4.实例四: |的用法
要求:判断一串字符串数组里面符合条件的字符串
代码如下:
String[] dataArr = { "been", "bean", "boon", "buin" ,"bynn"};
for (String str : dataArr) {
String patternStr="b(ee|ea|oo)n";
boolean result = Pattern.matches(patternStr, str);
if (result) {
System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
}
else{
System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
}
}
如果需要匹配多个字符,那么[]就不能用上了,这里我们可以用()加上|来代替,()表示一组,|表示或的关系,
模式b(ee|ea|oo)n就能匹配been,bean,boon等.
因此前三个能匹配上,而后两个不能.
5.实例五: \d的使用
要求:判断一串字符串数组里面符合条件的字符串
代码如下:
String[] dataArr = { "1", "10", "101", "1010" ,"100+"};
for (String str : dataArr) {
String patternStr="\d+";
boolean result = Pattern.matches(patternStr, str);
if (result) {
System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
}
else{
System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
}
}
注:从前面可以知道,\d表示的是数字,而+表示一次或多次,所以模式\d+就表示一位或多位数字.
因此前四个能匹配上,最后一个因为+号是非数字字符而匹配不上.
实例六: \w \d + 的使用
要求:判断一串字符串数组里面符合条件的字符串
代码如下:
String[] dataArr = { "a100", "b20", "c30", "df10000" ,"gh0t"};
for (String str : dataArr) {
String patternStr="\w+\d+";
boolean result = Pattern.matches(patternStr, str);
if (result) {
System.out.println("字符串"+str+"匹配模式"+patternStr+"成功");
}
else{
System.out.println("字符串"+str+"匹配模式"+patternStr+"失败");
}
}
模式\w+\d+表示的是以多个单字字符开头,多个数字结尾的字符串,因此前四个能匹配上,
最后一个因为数字后还含有单字字符而不能匹配.
7.实例七: \s的使用
要求:字符串的分割
代码如下:
String str="薪水,职位 姓名;年龄 性别";
String[] dataArr =str.split("[,\s;]"); //代表可以用,或空格或;分割字符串
for (String strTmp : dataArr) {
System.out.println(strTmp);
}
String类的split函数支持正则表达式,上例中模式能匹配”,”,单个空格,”;”中的一个,
split函数能把它们中任意一个当作分隔符,将一个字符串劈分成字符串数组.
8.实例八: []的使用
要求:字符串的分割
代码如下:
String str="2007年12月11日";
Pattern p = Pattern.compile("[年月日]");
String[] dataArr =p.split(str);
for (String strTmp : dataArr) {
System.out.println(strTmp);
}
Pattern是一个正则表达式经编译后的表现模式 ,它的split方法能有效劈分字符串.
注意其和String.split()使用上的不同.
9.实例九: ()的使用,这里不能使用[ ]
要求:字符串的分割
代码如下:
String str="10元 1000人民币 10000元 100000RMB";
str=str.replaceAll("(元|人民币|RMB)", "¥");
System.out.println(str);
上例中,模式“(元|人民币|RMB)”匹配元,人民币,RMB中的任意一个,替换部分表示第一个组匹配的部分不变,
其余组替换成¥.
替换后的str为¥10 ¥1000 ¥10000 ¥100000
10.实例十: Parttern类的compile方法的使用
Matcher类的find方法的使用
要求:替换匹配后的字符串
代码如下:
Pattern p = Pattern.compile("m(o+)n",Pattern.CASE_INSENSITIVE); //不区分大小写
// 用Pattern类的matcher()方法生成一个Matcher对象
Matcher m = p.matcher("moon mooon Mon mooooon Mooon");
StringBuffer sb = new StringBuffer();
// 使用find()方法查找第一个匹配的对象
boolean result = m.find();
// 使用循环找出模式匹配的内容替换之,再将内容加到sb里
while (result) {
m.appendReplacement(sb, "moon"); //把找到的内容替换成moon
result = m.find();
}
// 最后调用appendTail()方法将最后一次匹配后的剩余字符串加到sb里;
m.appendTail(sb);
System.out.println("替换后内容是" + sb.toString());
上面要匹配的5个字符串都符合正则表达式。
运行结果出现:5个moon字符
11.实例十一: {}的使用
除了用+表示一次或多次,*表示0次或多次,?表示0次或一次外,
还可以用{}来指定精确指定出现的次数,X{2,5}表示X最少出现2次,最多出现5次;
X{2,}表示X最少出现2次,多则不限;X{5}表示X只精确的出现5次.
要求:匹配字符串
代码如下:
String[] dataArr = { "google", "gooogle", "gooooogle", "goooooogle","ggle"};
for (String str : dataArr) {
String patternStr = "g(o{2,5})gle";
boolean result = Pattern.matches(patternStr, str);
if (result) {
System.out.println("字符串" + str + "匹配模式" + patternStr + "成功");
} else {
System.out.println("字符串" + str + "匹配模式" + patternStr + "失败");
}
}
12.实例十二: [ ]的使用
表示从..到…,如[a-e]等同于[abcde]
要求:字符串的匹配
代码如下:
String[] dataArr = { "Tan", "Tbn", "Tcn", "Ton","Twn"};
for (String str : dataArr) {
String regex = "T[a-c]n";
boolean result = Pattern.matches(regex, str);
if (result) {
System.out.println("字符串" + str + "匹配模式" + regex + "成功");
} else {
System.out.println("字符串" + str + "匹配模式" + regex + "失败");
}
}
13.实例十三:不区分大小写匹配.
正则表达式默认都是区分大小写的,使用了Pattern.CASE_INSENSITIVE则不对大小写进行区分.
要求:字符串的匹配
代码如下:
String patternStr="ab";
Pattern pattern=Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);
String[] dataArr = { "ab", "Ab", "AB"};
for (String str : dataArr) {
Matcher matcher=pattern.matcher(str);
if(matcher.find()){
System.out.println("字符串" + str + "匹配模式" + patternStr + "成功");
}
}
14.实例十四:\s*代表0到到多个空格
要求:使用正则表达式劈分字符串.
代码如下:
注意这里要把复杂的模式写在前面,否则简单模式会先匹配上.
String input="职务=GM 薪水=50000 , 姓名=职业经理人 ; 性别=男 年龄=45 ";
String patternStr="(\s*,\s*)|(\s*;\s*)|(\s+)";
Pattern pattern=Pattern.compile(patternStr);
String[] dataArr=pattern.split(input);
for (String str : dataArr) {
System.out.println(str);
}
15.实例十五:Matcher的group方法的使用
要求:取出尖括号外面的内容
代码如下:
String regex="<(\w+)>(\w+)</";
Pattern pattern=Pattern.compile(regex);
String input="<name>Bill</name><salary>50000</salary><title>GM</title>";
Matcher matcher=pattern.matcher(input);
while(matcher.find()){
System.out.println(matcher.group(2));
}
这题还是有点复杂的!
输出结果为: Bill 50000 GM
group(2)代表的是第二部分的\W+
如果group(1)代表的是第一部分的\W+
如果group(0)代表的是整个匹配的字符串
实例十六: []和+的使用
要求:将单词数字混合的字符串的单词部分大写.
代码如下:
String regex="([a-zA-Z]+[0-9]+)";
Pattern pattern=Pattern.compile(regex);
String input="age45 salary500000 50000 title";
Matcher matcher=pattern.matcher(input);
StringBuffer sb=new StringBuffer();
while(matcher.find()){
String replacement=matcher.group(1).toUpperCase();
matcher.appendReplacement(sb, replacement);
}
matcher.appendTail(sb);
System.out.println("替换完的字串为"+sb.toString());
输出结果:AGE45 SALARY500000 50000 title
五.一个检验Email地址的小程序:
最后我们来看一个检验Email地址的例程,该程序是用来检验一个输入的EMAIL地址里所包含的字符是否合法,
虽然这不是一个完整的EMAIL地址检验程序,它不能检验所有可能出现的情况,
但在必要时您可以在其基础上增加所需功能。
import java.util.regex.*; public class Email { public static void main(String[] args) throws Exception { Scanner scanner=new Scanner(System.in); String input = scanner.next(); //检测输入的EMAIL地址是否以 非法符号"."或"@"作为起始字符 Pattern p = Pattern.compile("^//.|^//@"); Matcher m = p.matcher(input); if (m.find()){ System.err.println("EMAIL地址不能以'.'或'@'作为起始字符"); } //检测是否以"www."为起始 p = Pattern.compile("^www//."); m = p.matcher(input); if (m.find()) { System.out.println("EMAIL地址不能以'www.'起始"); } //检测是否包含非法字符 p = Pattern.compile("[^A-Za-z0-9//.//@_//-~#]+"); m = p.matcher(input); 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); input = sb.toString(); if (deletedIllegalChars) { System.out.println("输入的EMAIL地址里包含有冒号、逗号等非法字符,请修改"); System.out.println("您现在的输入为: "+args[0]); System.out.println("修改后合法的地址应类似: "+input); } } } |
例如,我们在命令行输入:java Email www.kevin@163.net
那么输出结果将会是:EMAIL地址不能以'www.'起始
如果输入的EMAIL为@kevin@163.net
则输出为:EMAIL地址不能以'.'或'@'作为起始字符
当输入为:cgjmail#$%@163.net
那么输出就是:
输入的EMAIL地址里包含有冒号、逗号等非法字符,请修改
您现在的输入为: cgjmail#$%@163.net
修改后合法的地址应类似: cgjmail@163.net
例子是没有办法一一列出来了,但是java正则表达式的大部分用法都已经有覆盖到了。