正则表达式是用来操作字符串的规则,我们可以把正则表达式看做一个模板,把字符串放到这个模板中就可以得到我们想要的样子。
一. 正则表达式的简介
1.正则表达式的概念
正则表达式是一种规则,那么他用特定的符号来表示代码操作,这样就简化了书写,所以学习正则表达式就是学习一些特殊符号的使用,我们先来了解一下正则表达式的常用符号。
(1)字符类
[abc]表示此位置是否含有此字符
[^abc]表示此位置除了abc都可以接收
[a-zA-Z]接收全部字母,不区分大小写
[a-b[m-p]]表示可以接收a到b和M到p的字符集
[a-z&&[^bc]]表示接收a到z但是不包含bc
[a-z&&[^m-p]]表示接收a到z但是不包含m到p的子集
(2)预定义字符类
. 任何字符
\ d 数字0-9
\D 非数字
\s 空白字符[ \t\n\x0B\f\r]
\S 非空白字符
\w 单词字符[a-zA-Z_0-9] ,邮箱使用
\W 非单词字符
注意点:\ 单独出现时是转义字符,而\d是一个整体,所以要写\\d,在正则中只要出现“\”在使用的时候就得写“\\”
(3)Greedy 数量词
X? 表示X出现一次或一次也没有
X* 表示X出现零次或多次
X+ 表示X出现一次或多次
X{n} 表示X出现恰好 n 次
X{n,} 表示X出现至少 n 次
X{n,m} 表示X出现至少 n 次,但是不超过 m 次
(4) 组
组是正则当中一个非常强大的概念,我们可以把一个表达式封装成组,就是把它放在括号当中,组是有编号的,第一个括号包装的为第一组,在这个组之后还可以继续使用这个组的结果。
捕获组可以通过从左到右计算括号来编号。例如,在表达式 ((A)(B(C)))中,存在四个这样的组: 第一组:((A)(B(C))),第二组:(A),第三组: (B(C)),第四组: (C),利用“\\+组的编号”来表示是第几组,例如“\\1”就代表着第一组。而获取组中的内容可以使用”&”,他可以把组中的内容拿到。
2.正则表达式的使用
正则表达式可以应用于操作字符串的两个方法中,作为模板来格式化这个字符串,这两个方法分别是:
(1)匹配:matches(String regex)
返回boolean型,用规则匹配整个字符串,如果有一个不匹配就返回假。
我们通过对一个手机号码进行校验,使用正则的匹配功能,定义一个正则表达式,把手机号码的特点用正则进行描述,然后将手机号码的字符串表现形式按此正则表达式进行匹配。
/*
* 校验手机号
* 1.利用键盘录入信息
* 2.定义正则表达式,描述手机号
* 3.利用matches方法判断手机号是否正确
* */
public class Test1 {
public static void main(String[] args) {
//利用Scanner接收键盘录入手机号
Scanner sc = new Scanner(System.in);
while(true)
{
//获取录入数据
String str = sc.next();
//如果输入“out”程序结束不再录入
if("out".equals(str))
break;
/*定义正则表达式描述手机号信息
* [1]指第一位必须是数字1
* [358]指第二位数字必须是3或5或8
* \\d第二位后必须是数字
* {9}代表第二位后必须有9位数
* */
String regex = "[1][358]\\d{9}";
//判断是录入数据是否是手机号,利用String的matches方法
if(str.matches(regex))
{
System.out.println("您输入手机号正确!");
break;
}else
{
System.out.println("输入错误,请重新输入!");
}
}
}
}
(2)切割:split(String regex)
返回字符串数组,用指定的正则表达式来切割字符串。
注意点:在切割中我们常用正则来切割URL路径,当我们以“\”作为切割的标准时,在定义正则表达式时要写为“\\”,因为在正则中”\”代表转义字符,所以要多加一个“\”,而URL路径中的“\\”在正则中的表现形式是“\\\\”。
public class SplitDemo2 {
public static void main(String[] args) {
split_1();
System.out.println();
split_2();
}
/*
* 正则切割示例1
* 将字符串“小宏 小蓝 小绿 小黑”按空格切割,得到文字。
* */
private static void split_1() {
//定义字符串
String str = "小宏 小蓝 小绿 小黑";
//定义正则,因为要按空格切,空格数目不确定使用+来表示
String regex = " +";
split(str,regex);
/*
* 结果是:
* 小宏
小蓝
小绿
小黑
* */
}
/*
* 正则切割示例2
* 将一堆字符串按照叠词切割,例如将
* “heimazzxiaohongzzxiaoheizzxiaohua”
* 按照“zz”进行切割。利用组的概念。
* */
private static void split_2() {
String str = "heimazzxiaohongzzxiaoheizzxiaohua";
//定义正则,(.)组代表任意字符,\\1代表着后一位和组是一样的内容
String regex = "(.)\\1";
split(str,regex);
/*
* 结果是:
* heima
xiaohong
xiaohei
xiaohua
* */
}
//切割打印功能函数
private static void split(String str, String regex) {
String[] strs = str.split(regex);
for(String s : strs)
{
System.out.println(s);
}
}
}
(3)替换:replaceAll(String regex,String str)
返回字符串,以指定的字符串str替换掉字符串中正则表达式regex所匹配到的内容。
class Test3
{
public static void main(String[] args)
{
//将字符串中的数字替换成数组
String str1 = "xiaohong12adsf3321adfads";
replaceAll(str1,"\\d","#");
//将叠词替换成#
String str2 = "dfasdkkyasdaalslkddddqqffea";
replaceAll(str2,"(.)\\1+","#");
//将重叠字母替换成单个字母: "$1"
String str3 = "xiaohong hhhhh xiaolv yyyy xiaolan";
replaceAll(str3,"(.)\\1+","$1");
}
//替换功能函数
public static void replaceAll(String str,String reg,String newStr)
{
str = str.replaceAll(reg,newStr);
System.out.println(str);
}
/*
* 结果是:
* xiaohong##adsf####adfads
dfasd#yasd#lslk###ea
xiaohong h xiaolv y xiaolan
*
* */
}
(4)获取
通过正则表达式把符合要求的子串从字符串中取出具体操作步骤为:
1>将正则表达式封装成对象,把正则表达式封装成对象的类叫做Pattern,这个类是一个工具类,在这个类中有一个方法compile(String regex),他可以将指定的正则表达式封装成Pattern对象。
2>让正则对象和要操作的字符串相关联,通过Pattern类中的matcher(CharSequence input)方法,将字符串作为参数传入matcher方法中。
3>关联后获取正则匹配引擎,当调用matcher方法时会返回一个Matcher对象,这个Matcher就是一个匹配引擎,他具有更多的方法来操作与之匹配的字符串。
4>启动引擎对符合规则的子串进行操作,我们可以通过Matcher的方法find()方法来将规则作用到字符串上,并进行符合规则的子串查找,然后调用group()方法来返回符合规则的子串,这样就完成了利用正则来获取指定子串。
/*
* 利用指定的规则来获取字符串中的子串
* 获取“heima nihao wo shi xiao hong wo lai le”
* 中由四位字符组成的词组
* */
public class Test4 {
public static void main(String[] args) {
String str = "heima nihao,wo shi xiao hong,wo lai le!";
//定义正则,定义四字单词需要用到边界字符“\b”
String regex = "\\b[a-z]{4}\\b";
//把正则封装成对象
Pattern pt = Pattern.compile(regex);
//获取匹配引擎
Matcher mc = pt.matcher(str);
//将正则作用于字符串上,并进行符合规则的查找
while(mc.find())
{
//取出符合规则的子串
String ss = mc.group();
System.out.println(ss);
}
}
}
/*
* 打印:
* xiao
hong
* */
3.正则的弊端
当我们需要的规则越多,定义的正则表达式就越长,这样阅读性越差,一个复杂的正则表达式让人不能一眼就看出他的作用。而且使用正则之后当输入错误无法精准的定位错误出现的原因。
二. 正则表达式的练习
1. 去掉标点和叠词
/*
* 将以下字符串去重复和省略号
* “我我...我我...要....学学学...编....编...程“
* */
public class Test5 {
public static void main(String[] args) {
String str = "我我...我我...要....学学学...编....编...程";
/*分析正则表达式如何定义
* 1.需要去省略号
* 2.去叠词
* */
//去省略号,使用替换
String newStr1 = str.replaceAll("[.]+","");
System.out.println(newStr1);
//去叠词,使用组
String newStr2 = newStr1.replaceAll("(.)\\1+", "$1");
System.out.println(newStr2);
}
}
/*
* 打印:
* 我我我我要学学学编编程
我要学编程
*/
2.对IP地址进行排序
/*
* 使用正则对一堆ip地址进行排序
* 192.168.0.1 102.23.45.23 10.10.20.10 2.3.3.3 9.132.43.21
*
* 让ip地址按照字符串自然顺序,2排到10的后面,所以要让他们每一段都是3位,
* 即010对应002时,002就排到010的前面。
* 思路:
1.利用正则将每一段的ip地址前补两个0
2.将每一段只保留3位
3.将3位的ip地址进行排序
4.将ip地址进行还原
* */
public class Test6 {
public static void main(String[] args) {
String ip = "192.168.0.1 102.23.45.23 10.10.20.10 2.3.3.3 9.132.43.21";
//补两个0
String newIp1 = ip.replaceAll("(\\d+)", "00$1");
//保留三位
String newIp2 = newIp1.replaceAll("0*(\\d{3})", "$1");
//将三位数的ip地址进行排序
String[] strs = newIp2.split(" +");
Arrays.sort(strs);
//遍历排完序的数组,并将他们还原
for(String s:strs)
{
System.out.println(s.replaceAll("0*(\\d+)", "$1"));
}
}
}
/*
* 打印:
* 2.3.3.3
9.132.43.21
10.10.20.10
102.23.45.23
192.168.0.1
*
* */
3.网页爬虫,获取网页中邮箱
我们可以利用正则来匹配网页上的数据,来获取邮箱名,邮箱的正则表达式较为精准的是“\\w+@\\w+(\\.[a-zA-Z]+){1,3}”,这种格式获取到的邮箱绝大多数为正常的。我们来看一下如何在网页上获取邮箱:
/*
* 建立一个网页爬虫,获取网页中的邮箱
* 1.自定义一个URL访问网页
* 2.获取网页中的内容
* 3.定义正则匹配网页中信息,获取到邮箱
* 4.将获取到的邮箱打印出来并写入本地文件中
* */
public class Test7 {
public static void main(String[] args) {
PrintWriter pw = null;
BufferedReader br = null;
try {
//定义输入流,将获取到的邮箱写入到本地文件
pw = new PrintWriter(new FileWriter("e://email.txt"),true);
//自定义客户端访问网页
URL u = new URL("http://www.itheima.com/newhelp/393.html");
URLConnection uc = u.openConnection();
br = new BufferedReader(
new InputStreamReader(uc.getInputStream()));
String line = null;
//定义正则用来匹配邮箱
String regex = "\\w+@\\w+(\\.[a-zA-Z]+){1,3}";
//把正则封装成对象
Pattern p = Pattern.compile(regex);
while((line = br.readLine())!=null)
{
//拿到引擎匹配当前行
Matcher mc = p.matcher(line);
while(mc.find())
{
String str = mc.group();
System.out.println(str);
pw.println(str);
}
}
} catch (Exception e) {
e.printStackTrace();
}finally
{
pw.close();
try {
if(br==null)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 打印:
* heima@csdn.net
* */