正则表达式:在代码中常写为regex、regexp、或RE,从JDK1.4开始引入。
目的:更加灵活的实现字符串的匹配、拆分、替换等操作。

问题引出

我常说,我们以开发者角度看代码,或知识点,最重要一条就是:常问自己,这个东西有什么用?
正则表达式实际上是一组规范。

给一道例题:要求判断某一个字符串是否由数字组成。
我们需要注意两点:1.为了能够判断每一位字符数据,需要将字符串转换为字符数组,这样便于循环判断。
2.判断字符数组中的每一个字符是否在“0-9”之间
重点来了,“0-9”

public class Main{

public static void main(String[] args) {
String str="123yook";
System.out.println(isNumber(str));
}
public static boolean isNumber(String temp){
if(temp==null||"".equals(temp)){
return false;
}
char data[]=temp.toCharArray(); //字符串变为字符数组
for(int x=0;x<data.length;x++){
if(data[x]>'9'||data[x]<'0'){
return false;
}
}
return true;
}
}

上面一段代码大家都不陌生,但是:就这样一个简单的操作,却要开发者编写超过10行的代码,是不是有点麻烦了?
简化:正则

public static void main(String[] args){
String str="123yook";
System.out.println(str.matches("\\d+"));
}

好不好玩?

好,我们先说说有什么用:
1.在注册登录页面,用户是不是需要填一个“密码”框,这个里面一般都需要纯数字,而且,就算可以有字符,正则还是可以应付这些(我们下面会提到)
2.还是注册页面,判断用户是不是按要求输入了身份证号,怎么办?——用正则呀
3.在一份文件中,需要统计比如说一共有多少个单词,怎么办?——用正则


匹配字符串

让我们从String类中的matches方法开始。乍一看,这个方法很类似于equals方法。例如:

"java".matches("java");
"java".equals("java");

这两句的结果就都为true;

But,matches方法强大在于,它不仅可以匹配固定字符串,还可以匹配一个模式的字符串集,例如:

"java is fun".matches("java.*");
"java is cool".matches("java.*");
"java is powerful".matches("java.*");

语句中的“java.”就是正则表达式。它描述了一个字符串模式,以java开始,后面跟0个或多个字符串。这里,子字符串“.”匹配任何0个或多个字符(下面会提到)

正则表达式语法

由字面值字符和特殊符号组成。下面列出一些常用语法:
注意:反斜杠是一个特殊的字符,在字符串中开始转义序列。因此,java中需要使用\d来表示\d)
注意:回顾下,空白字符是:’ ‘、’\t’、’\n’、’\r’,或者:’\f’。因此,\s和[\t\n\r\f]等同,\S和[^\t\n\r\f]等同——别着急,往下看)

. ->任一单个子符(java匹配j…a)
(ab|cd) ->ab或cd(tent匹配t(en|rm)t)
[abc] ->a、b或c
[^ abc] ->除a、b、c以外的任意字符(java匹配ja[^ars]a)
[a-z] ->小写字母a-z
[a-e[m-p]] ->a-e或m-p(java匹配[a-g[i-m]]av[a-d])
[a-e&&[c-p]] ->a-e与c-p的交集(java匹配[a-p&&[i-m]]av[a-d])
\d ->单个数字,等同于:[0-9]
\D ->一位非数字
\w ->单词字符
\W ->非单词字符
p* ->模式p的0次或多次出现
p+ ->模式p的1次或多次出现
p? ->模式p的0次或1次出现
p{n} ->模式p的正好n次出现
p{n,} ->模式p的至少n次出现
p{n,m} ->模式p出现次数位于n和m之间(不包含)

注意:单词字符是任何的字母,数字或下划线字符。因此\w等同于[a-z[A-Z][0-9]]或者简化为[a-Za-z0-9])
注意:不要在重复量词符中使用空白。例如:A{3,6}不能写成逗号后面有一个空白符的A{3, 6})
注意:可以使用括号来将模式进行分组。例如:(ab){3}匹配ababab,但是ab{3}匹配abbb)

示例

让我们用一些示例来演示如何构建正则表达式。

示例一
社会安全号的模式是:xxx-xx-xxxx,其中x是一位数字。
先想。。。

可以描述为:[\\d]{3}-[\\d]{2}-[\\d]{4}

示例二
偶数数字以0/2、4、6、8结尾。偶数的模式可以描述为:
先想。。。

[\\d]*[02468]

硬核,替换和分割字符串

我们知道,在java的String类中,包含有replaceAll、replaceFirst、和split方法,用于分割和替换字符串:
用replaceAll替换所有匹配的字符串,而用replaceFirst方法替换第一个匹配的子字符串。
那放在正则里怎么用呢?

例如,下面代码:

System.out.println("java java java".replaceAll("v\\w","wi"));

结果:jawi jawi jawi

java中的分割方法A:split,这里不再详说。。。

还要注意一点默认的,所有的量词都是“贪婪的”。这意味着它们会尽量匹配可能的最多次。比如,下面语句显示jrvaa。因为第一个匹配成功的是aaa。

System.out.println("jaaavaa".replaceFirst("a+","r"));

我们可以通过**在后面添加问号符号 **来改变量词的默认行为。量词符变为“不情愿”的,这意味着它将匹配尽可能 少的次数。例如,下面的语句显示jraavaa,因为第一个匹配成功的是a。

System.out.println("jaaavaa".replaceFirst("a+?","r"));

大招 - 实践操作

package 一些小程序;

/**
* @author Mengxc
* @seeean 判断身份证(--正则判断)
* 第7-12位代表出生年月日
* 新18位身份证号码中,1、2位代表省,3、4位代表市,5、6位代表区,7、8、9、10位代表出生年份(15位身份证的用2位代表年份),
* 11、12位代表出生月份,13、14位代表出生日期,
* 15、16、17、18位代表序列号(15位身份证用3位代表序列号)其中第17位(15位身份证的最后一位)为单数时表示男性,双数时表示女性。
*/

public class DemoS {
public static void main(String[] args) throws Exception{
String text="421222145506112911";
text="320311770706001";
String text1,text2,text3;
System.out.println(text.length()+"位身份证号");
//判断长度
boolean matches=text.matches("\\d{17}[a-zA-Z0-9]|\\d{14}[a-zA-Z0-9]"); //\\d表示正则表达式中的“【0-9】”,与此相对,\\D-[^0-9]
if(matches)
{
//15位,提取7-12
if(15==text.length()){
// text=text.substring(6,12);
text1=text.substring(6,8);
text2=text.substring(8,10);
text3=text.substring(10,12);
}else{
//18位,提取7-14
// text=text.substring(6,14);
text1=text.substring(6,10);
text2=text.substring(10,12);
text3=text.substring(12,14);
}
System.out.println(text1+"年-"+text2+"月-"+text3+"日");
}
}
}