今天开发过程遇到了正则表达式 虽然以前学过 但习惯了百度 早已忘了 这次重新捡起来
随便写几个练下手。
推荐一个java正则表达式的网址 菜鸟教程
http://www.runoob.com/java/java-regular-expressions.html
public class AppTest {
/**
* 正则表达式 匹配手机号
* ^1 匹配开始的位置 必须以1开头
* x|y 匹配是x 或y
* [xyz] 自定义集合 匹配包含的任意一个字符 例如:“a” 匹配[abc] 而“f”就不能匹配[abc]
* [0-9]匹配0到9中任意一个
* 理解在 Java 的正则表达式中,两个 \\ 代表其他语言中的一个 \
* 这也就是为什么表示一位数字的正则表达式是 \\d,而表示一个普通的反斜杠是 \\\\。
* {n,m} n<=m 最少匹配4次 最多匹配八次
* \\d 匹配一次数字(非负)
*/
@Test
public void regtest() {
// String regExp = "^1[3|4|5|7|8][0-9]\\d{4,8}$";
//现在有199的手机号 用这个匹配
String regExp = "^1(([35789][0-9])|(47))\\d{8}$";
// String regExp="^\\d"; //以非负数字开头
Pattern p = Pattern.compile(regExp);
Matcher m = p.matcher("0");
System.out.println( m.matches());
}
/**
* .(点号)也是一个正则表达式,它匹配任何一个字符如:"a" 或 "1"
* +(加号)一次或多次匹配前面的字符 例如"za+"可以匹配"zaa",也可以匹配"za" 但不能匹配“z”
* ?(零次或一次匹配前面的字符或子表达式)
* \\. 其它语言的\. 就是字面意思 点号
* +? 非贪婪匹配 尽可能少的匹配
*/
@Test
public void regUrl(){
String regExp="^http://.+?\\.pc.+?\\.com\\.cn.*";
Pattern p = Pattern.compile(regExp);
Matcher m = p.matcher("http://bfakbd.pc");
System.out.println( m.matches());
}
/**
* 匹配形如xxx@.xxx.com的邮箱 邮箱只能是qq邮箱或者是163邮箱
*/
@Test
public void email(){
String regExp="([a-zA-z0-9]{1,})@(qq|163).com";
Pattern p = Pattern.compile(regExp);
Matcher m = p.matcher("10431@163.com");
System.out.println( m.matches());
/*自定义集合[abc] 匹配测试*/
regExp="[abc]";
p=Pattern.compile(regExp);
m = p.matcher("f");
System.out.println("[abc]匹配: "+m.matches());
}
}
正则表达式还可以用来替换字符串:
例如:替换手机号码中四位为*
mobile.replaceAll("(\d{3})\d{4}(\d{4})", " $1****$2"))
括号表示组,被替换的部分$n表示第n组的内容。
//java正则表达式查询
//完全匹配字符串中某个单词
Pattern compile = Pattern.compile("world");
Matcher matcher = compile.matcher("hello world I AM Evan zhou ");
boolean find = matcher.find();
System.out.println(find);
总结:
以下是一些创建字符类的典型方式,以及一些预定义的类
进阶
- 零宽断言
断言:俗话的断言就是“我断定什么什么”,而正则中的断言,就是说正则可以指明在指定的内容的前面或后面会出现满足指定规则的内容,
意思正则也可以像人类那样断定什么什么,比如"ss1aa2bb3",正则可以用断言找出aa2前面有bb3,也可以找出aa2后面有ss1.
零宽:就是没有宽度,在正则中,断言只是匹配位置,不占字符,也就是说,匹配结果里是不会返回断言本身。
爬虫抓取文章阅读量
"<span class="read-count">阅读数:641</span>"
String reg="\\d+(?=</span>)";
String test = "<span class=\"read-count\">阅读数:641</span>";
Pattern pattern = Pattern.compile(reg);
Matcher mc= pattern.matcher(test);
while(mc.find()){
System.out.println(mc.group());
}
//匹配结果:641
//(?<=<span class="read-count">阅读数:)\d+
String reg="(?<=<span class=\"read-count\">阅读数:)\\d+";
String test = "<span class=\"read-count\">阅读数:641</span>";
Pattern pattern = Pattern.compile(reg);
Matcher mc = pattern.matcher(test);
while(mc.find()){
System.out.println(mc.group());
}
//匹配结果:
//641
祖国(?!的花朵)
2. 捕获和非捕获
单纯说到捕获,他的意思是匹配表达式,但捕获通常和分组联系在一起,也就是“捕获组”
而根据命名方式的不同,又可以分为两种组:
1、数字编号捕获组:
语法:(exp)
解释:从表达式左侧开始,每出现一个左括号和它对应的右括号之间的内容为一个分组,在分组中,第0组为整个表达式,第一组开始为分组。
比如固定电话的:020-85653333
他的正则表达式为:(0\d{2})-(\d{8})
按照左括号的顺序,这个表达式有如下分组:
String test = "020-85653333";
String reg="(0\\d{2})-(\\d{8})";
Pattern pattern = Pattern.compile(reg);
Matcher mc= pattern.matcher(test);
if(mc.find()) {
System.out.println("分组的个数有:"+mc.groupCount());
for(int i=0;i<=mc.groupCount();i++) {
System.out.println("第"+i+"个分组为:"+mc.group(i));
}
}
//分组的个数有:2
//第0个分组为:020-85653333
//第1个分组为:020
//第2个分组为:85653333
2、命名编号捕获组:
语法:(?exp)
解释:分组的命名由表达式中的name指定
比如区号也可以这样写:(?\0\d{2})-(?\d{8})
按照左括号的顺序,这个表达式有如下分组:
String test = "020-85653333";
String reg="(?<quhao>0\\d{2})-(?<haoma>\\d{8})";
Pattern pattern = Pattern.compile(reg);
Matcher mc= pattern.matcher(test);
if(mc.find()){
System.out.println("分组的个数有:"+mc.groupCount());
System.out.println(mc.group("quhao"));
System.out.println(mc.group("haoma"));
//分组的个数有:2
//分组名称为:quhao,匹配内容为:020
//分组名称为:haoma,匹配内容为:85653333
比如上面的正则表达式,程序不需要用到第一个分组,那就可以这样写:
(?:\0\d{2})-(\d{8})
String test = "020-85653333";
String reg="(?:0\\d{2})-(\\d{8})";
Pattern pattern = Pattern.compile(reg);
Matcher mc= pattern.matcher(test);
if(mc.find()) {
System.out.println("分组的个数有:"+mc.groupCount());
for(int i=0;i<=mc.groupCount();i++) {
System.out.println("第"+i+"个分组为:"+mc.group(i));
}
}
//分组的个数有:1
//第0个分组为:020-85653333
//1个分组为:85653333
3. 反向引用
上面讲到捕获,我们知道:捕获会返回一个捕获组,这个分组是保存在内存中,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式内部进行引用,这种引用方式就是反向引用。
根据捕获组的命名规则,反向引用可分为:
比如要查找一串字母"aabbbbgbddesddfiid"里成对的字母
如果按照我们之前学到的正则,什么区间啊限定啊断言啊可能是办不到的,
现在我们先用程序思维理一下思路:
这里的思路2中匹配下一个字母时,需要用到上一个字母,那怎么记住上一个字母呢???
这下子捕获就有用处啦,我们可以利用捕获把上一个匹配成功的内容用来作为本次匹配的条件
好了,有思路就要实践
首先匹配一个字母:\w
我们需要做成分组才能捕获,因此写成这样:(\w)
那这个表达式就有一个捕获组:(\w)
然后我们要用这个捕获组作为条件,那就可以:(\w)\1
这样就大功告成了
可能有人不明白了,\1是什么意思呢?
还记得捕获组有两种命名方式吗,一种是是根据捕获分组顺序命名,一种是自定义命名来作为捕获组的命名
在默认情况下都是以数字来命名,而且数字命名的顺序是从1开始的
因此要引用第一个捕获组,根据反向引用的数字命名规则 就需要 \k<1>或者\1
当然,通常都是是后者。
String test = "aabbbbgbddesddfiid";
Pattern pattern = Pattern.compile("(\\w)\\1");
Matcher mc= pattern.matcher(test);
while(mc.find()){
System.out.println(mc.group());
}
//aa
//bb
//bb
//dd
//dd
//ii
String test = "abcbbabcbcgbddesddfiid";
String reg="(a)(b)c";
System.out.println(test.replaceAll(reg, "$1"));;
//abbabcgbddesddfiid