您的位置:首页 > 编程语言 > Java开发

Java基础:正则表达式

2015-05-09 20:31 363 查看
第一部分:正则表达式概述

一、概念

正则表达式:符合一定规则的表达式。

二、作用

专门用于操作字符串。虽然String类中有许多操作字符串的方法,但是这些方法操作起来比较复杂。

对字符串进行操作即便捷、又简单的方式就是正则表达式。

示例:校验QQ号码(传统方法)

package day.day15;
/*
* 对QQ号码进行校验
* 要求:5-15位  0不能开头,只能是数字
*/
public class CheckQQ {
public static void main(String[] args) {
checkQQByParse("12e452354");
}

//第一种方式(使用Sring类中的方法组合完成需求,代码过于复杂)
public static void checqQQ(String qq){
int len = qq.length();
//判断长度
if(len>=5 && len<=15){
//是否0开头
if(!qq.startsWith("0")){
//是否是数字
char[] arr = qq.toCharArray();
boolean flag = true;
for(int x=0;x<arr.length;x++){
if(!(arr[x]>='0' && arr[x]<='9')){
flag = false;
break;
}
}
if(flag){
System.out.println("qq:"+qq);
}else{
System.out.println("出现非法字符");
}
}else{
System.out.println("不可以0开头");
}
}else{
System.out.println("长度错误");
}
}

//第二种方式,转换成数字判断
public static void checkQQByParse(String qq){
int len = qq.length();
if(len>=5 && len<=15){
if(!qq.startsWith("0")){
try{
//直接转换成long型,如果出现字母会抛出数字格式异常(判断字符串是否是纯数字)
Long num = Long.parseLong(qq);
System.out.println("qq::"+qq);
}catch(NumberFormatException e){
System.out.println("出现非法字符...");
}
}else{
System.out.println("不能以0开头");
}
}else{
System.out.println("长度错误");
}
}
}

正则表达式校验QQ号码:

package day.day15;
/*
* 通过正则表达式校验QQ号码
* 	boolean matches(String regex)
告知此字符串是否匹配给定的正则表达式
*/
public class CheckQQNew {
public static void main(String[] args) {
checkQQ("23354245");
}
public static void checkQQ(String qq){
/*
* 第一位:1-9	第二位:是数字就可以,而且出现4-14次
*/
String regex = "[1-9][0-9]{4,14}";
//校验字符串是否符合指定规则
boolean flag = qq.matches(regex);
if(flag){
System.out.println(qq+"...is OK");
}else{
System.out.println("nono.....不合法");
}
}
}


三、优缺点

1、优点

        正则表达式其实就是在用一些特定的符号表示一些代码操作,简化了书写。如JSP中用一些标签代表Java类可以简化书写。(底层的原理还是方法)

学习正则表达式就是学习这些特殊符号的使用。

2、缺点

符号定义越多,正则越长,阅读性极差。

四、正则表达式的构造摘要(构造与匹配)

1、字符






2、字符类






注意:一个[]只能校验一个字符

3、预定义字符



注意:

1)定义类似\d的规则时,要用\\d表示

2)\f代表换页符;\r代表回车符

3)\w(数字、字母、下划线)可用于校验邮箱名

4、边界匹配器



5、Greedy 数量词



注意:X代表一个规则或字符,如[a-zA-Z]?表示该位是字母,可能出现1次或0次。

6、反斜线、转义和引用

1)在不表示转义构造的任何字母字符前使用反斜线都是错误的;它们是为将来扩展正则表达式语言保留的。可以在非字母字符前使用反斜线,不管该字符是否非转义构造的一部分。

2)在java中\代表转义字符,在使用带有\的符号时,必须转义。

3)“.”在正则表达式中代表任意字符,要用“.”切割则需要转义成\\.才代表字符串中的“.”字符。(“abc
4000
.def”)

4)在正则表达式中\必须是成对出现的。

7、组合捕获

1)在定义规则(正则表达式)时,如果后一个字符需要使用前一个字符的结果(与前一个字符相同)。即当想要对一个规则的结果进行重用时,可以将其封装成一个组,用()完成。

2)封装成组后就存在一个自动的编号从1开始。可以通过\的形式反向引用组。

\n 捕获组。想要使用组可以通过\n的形式获取(n就是组的编号)。

3)捕获组时在字符串中需要使用\\表示\。

4)多个组出现时,如:((())()),有几个组就看有几个左括号,第一个(是第一个组,第二个(就是第二个组。

5)虽然组的操作都比较简单,底层已经完成。但是阅读性极差。

6)获取前一个规则中的组,$n(表示获取前一个规则中第n组中的字符)。如:"(.)\\1+","$1"第一个规则表示叠词,第二个规则表示获取前一个规则第1个组中的字符。

第二部分:正则表示式操作

一、匹配

String类中:

boolean matches(String regex) 
          告知此字符串是否匹配给定的正则表达式(拿一个规则匹配整个字符串,某一个位置不符合规则,校验结束,返回false)

示例代码:

package day.day15;
/*
* 匹配电话号码:
* 13xxxxx
* 15xxxxx
* 18xxxxx
*/
public class CheckTel {
public static void main(String[] args){
checkTel("18608500129");
}
public static void checkTel(String tel){
//第一位1,第二位3或5或8,其他9位是数字
String regex = "[1][358]\\d{9}";
boolean flag = tel.matches(regex);
System.out.println(flag);
}
}


二、切割:

String类中:

String[] split(String regex)        根据给定正则表达式的匹配拆分此字符串

示例代码:

package day.day15;
/*
* 用正则表达式切割字符串("\"在正则表达式中是成对出现的)
* 	String[] split(String regex)        根据给定正则表达式的匹配拆分此字符串
String[] split(String regex, int limit)        根据匹配给定的正则表达式来拆分此字符串

规则:空格出现一次多多次(多个空格进行切割)String regex = " +";
*/
public class SplitDemo {
public static void main(String[] args){
//1、用.切割
String str1 = "zhangsan.lisi.wangwu";
String regex1 = "\\.";//在正则表达式中代表任意字符,要用.切割则需要转义成\\.才代表字符串中的.字符
splitRegex(str1,regex1);

//2、用空格切割,出现1次或多次
splitRegex("zhangsan  lisi    wangwu"," +");

//3、用\\切割
String str2 = "c:\\abc\\e\\d";
String regex2 = "\\\\";//两个\转义后代表一个\
splitRegex(str2,regex2);

//4、按叠词切割
//split与matches方法不一样,matches方法捕获到不符合规则的字符就结束,split方法会继续向下匹配
splitRegex("helloguiyangbbbaceccc","(.)\\1+");//叠词出现不定的次数(第一组任意字符、第二个字符与第一组相同,出现1次或多次
}

public static void splitRegex(String str,String regex) {

String[] strs = str.split(regex);
for(String s:strs){
System.out.println(s);
}
}
}


三、替换

String类中:

String replaceAll(String regex, String replacement) 

          使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串

String replaceFirst(String regex, String replacement) 

          使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串

示例代码:

package day.day15;
/*
* 正则表达式:替换字符串
* 将字符串中的数字信息(电话号码、qq等)替换成#
* 		String replaceAll(String regex, String replacement)
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串
*/
public class ReplaceString {
public static void main(String[] args) {
String str = "hello3230928349world345546";
//用#替换符合指定正则表达式(规则)的字符串
replaceAllDemo(str,"\\d{5,}","#");

//将叠词替换成&
replaceAllDemo("playdddbasketballjjjnbawwww","(.)\\1+","&");

//将叠词替换成单个字符,获取前一个组中的字符$
replaceAllDemo("playdddbasketballjjjnbawwww","(.)\\1+","$1");//$1获取前一个规则中的第一个组(在外面获取)
}
public static void replaceAllDemo(String str,String regex,String replaceStr){
str = str.replaceAll(regex,replaceStr);
System.out.println(str);
}
}

运行结果:



四、获取

1、 操作步骤:

 1)将正则表达式封装成对象

 2)让正则对象和要操作的字符串相关联

 3)关联后,获取正则匹配引擎

 4)通过引擎对符合规则的子串进行操作,比如取出

2、Pattern类(java.util.regex)

正则表达式的编译表示形式。

CharSequence:接口,字符序列。String的父类。

常用方法:

static Pattern compile(String regex)        将给定的正则表达式编译到模式中 (将规则封装成对象)

Matcher matcher(CharSequence input)        创建匹配给定输入与此模式的匹配器(获取匹配对象)

3、Matcher类(java.util.regex)

匹配器。通过解释 Pattern 对 character sequence 执行匹配操作的引擎。

常用方法:

boolean find()        尝试查找与该模式匹配的输入序列的下一个子序列

String group()         返回由以前匹配操作所匹配的输入子序列(获取匹配后的结果)

boolean matches()        

          尝试将整个区域与模式匹配。String类中的matches方法(replaceAll)是用的Pattern与Matcher类实现的

int start()        返回以前匹配的初始索引

int end()        返回最后匹配字符之后的偏移量

示例代码:

package day.day15;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
* 正则表达式:获取(按指定规则获取子串)
* 			 将字符串中符合规则的子串取出
*
* 匹配、切割、替换都只能按照规则去操作字符串
*
* 操作步骤:
* 1、将正则表达式封装成对象
* 2、让正则对象和要操作的字符串相关联
* 3、关联后,获取正则匹配引擎
* 4、通过对引擎符合规则的子串进行操作,比如取出。
*/
public class GetString {
public static void main(String[] args) {
getDemo();
}
public static void getDemo(){
String str = "ming tian yao fang jia le ,da jia";
String regex = "\\b[a-z]{4}\\b";// \b代表单词边界

//将规则封装成对象(无构造函数,静态方法返回本类对象)
Pattern p = Pattern.compile(regex);

//让正则对象与要作用的字符串相关联。获取匹配器对象(并没有进行匹配操作)
Matcher m = p.matcher(str);

//匹配后不满足规则(4个字母单词)返回假,但是匹配器已经走到tian的t上(索引位置在改变),用find从新的索引位开始查找(同一匹配器使用同一指针)
System.out.println("matches:"+m.matches());

//find方法匹配一次,matches方法是整个匹配
while(m.find()){//将规则作用域字符串上并进行符合规则的子串查找

System.out.println(m.group());//用于获取匹配后的结果

System.out.println(m.start()+"..."+m.end());//符合规则的字符串的头角标与尾角标(不含尾)(索引位)
//切割字符串就是将start→end之间的部分去掉,获取就只取start→end
}

//System.out.println(m.matches());//String类中的matches方法,用的就是Pattern和Matcher对象完成的
}
}
运行结果:



图解:



注意:

1)同一个匹配器对象使用的是同一个索引。如在对匹配器进行matches操作后,指针在匹配后的结果处,接着使用find方法会从当前位置开始往下查找。

2)获取类似于集合中的迭代器。

3)String类中替换、切割、匹配方法都是通过Pattern类与Matcher类实现的。

4)切割是获取规则以外的子串,获取是获取符合规则的子串。

五、总结

到底使用匹配、替换、切割与获取中的哪一个功能呢?思路如下:

1、如果想知道该字符串是否对与错,使用匹配。

2、想要将已有的字符串变成另一个字符串,使用替换。

3、想要按照指定的方式将字符串变成多个字符串,使用切割。(获取规则以外的字符串)

4、想要拿到符合规则需求的字符串,使用获取。(获取符合规则的字符串)

示例代码1:

package day.day15;

import java.util.TreeSet;

/*
* 正则表达式练习
*/
public class RegexDemo {
public static void main(String[] args) {
test_1();
test_2();
}
/*
* 需求:将下列字符串转换成 我要学编程
* 思路:将已有的字符串变成另一个字符串。使用 替换 功能
* 1、可以先去掉.
* 2、去掉重复字符
*
*/
public static void test_1(){
String str = "我我...我我...我要..要要..要要...学学学...编编编...程程.程...程.....程";
str = str.replaceAll("\\.+", "");//去掉.

//第一个字符与第二个字符相同(或者...第n个),用第一个字符替代
str = str.replaceAll("(.)\\1+", "$1");//去掉重复的字只保留一个
System.out.println(str);
}
/*
* 192.68.1.254 102.49.34.013 10.10.10.10 2.2.2.2 8.109.90.30
* 将IP地址进行地址段顺序的排序
*
* 思路:按照字符串的自然顺序,只有它们每一段都是3位即可
* 1、按照每一段需要的最多的0补齐,那么每一段就会至少有3位
* 2、将每一段只保留3位
*/
public static void test_2(){
String ip ="192.68.1.254 102.49.34.013 10.10.10.10 2.2.2.2 8.109.90.30";
//给
a8a4
每个数字都补两个 0
ip = ip.replaceAll("(\\d+)", "00$1");
//每一个数字只保留3位(后3位封装成一个组)
ip = ip.replaceAll("0*(\\d{3})", "$1");

//切割
String[] ips = ip.split(" +");

//进行自然顺序的比较(可以通过集合,先存入集合)
TreeSet<String> set = new TreeSet<String>();//有重复元素则采用Arrays.sort方法
for(String str:ips){
set.add(str);
}

//对集合进行遍历
for(String s:set){
//去除前面多余的0并输出
System.out.println(s.replaceAll("0*(\\d+)", "$1"));
}
}
}

运行结果:



示例代码2:(匹配邮箱)

package day.day15;
/*
* 需求:匹配邮箱
*/
public class MailMatches {

public static void main(String[] args) {

String mail = "abc132@qq.com";
//较为精确的匹配
String regex = "[a-zA-Z_0-9]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,3}";//将.com封装成一个组

//相对不大精确的匹配
regex = "\\w+@\\w+(\\.\\w+){1,3}";
boolean flag = mail.matches(regex);
System.out.println(flag);
}
}


六、网页爬虫(蜘蛛)

在互联网中获取符合指定规则的数据。

示例代码:

package day.day15;
/*
* 网页爬虫:获取网页中的指定信息(如获取某一个指定网页中的邮箱)
*/
import java.io.*;
import java.util.regex.*;
import java.net.*;
public class HtmlRegex {

public static void main(String[] args)  throws Exception{
netMail();
}
//获取某一个网页中的邮箱
public static void netMail() throws Exception{
//获取资源定位符对象
URL url = new URL("http://192.168.1.104:8080/myweb/mail.html");

//获取连接对象
URLConnection conn = url.openConnection();
BufferedReader bufr =
new BufferedReader(new InputStreamReader(conn.getInputStream()));

String line = null;
//定义邮箱的正则表达式
String regex = "\\w+@\\w+(\\w+){1,3}";
//获取正则对象
Pattern p = Pattern.compile(regex);

//读取网页文件中的数据
while((line=bufr.readLine())!=null){
//获取正则匹配器
Matcher m = p.matcher(line);
//通过匹配器中的方法获取数据
while(m.find()){
System.out.println(m.group());
}
}
}

//获取硬盘中的邮箱
public static void showMail() throws Exception{
BufferedReader bufr =
new BufferedReader(new FileReader("mail.txt"));
String line = null;
//定义邮箱的正则表达式
String regex = "\\w+@\\w+(\\w+){1,3}";
//获取正则对象
Pattern p = Pattern.compile(regex);

//读取硬盘文件中的数据
while((line=bufr.readLine())!=null){
//获取正则匹配器
Matcher m = p.matcher(line);
//通过匹配器中的方法获取数据
while(m.find()){
System.out.println(m.group());
}
}
}
}

运行结果:


                      
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: