一、概述
- 概念:符合一定规则的表达式。
- 作用:用于专门操作字符串。
- 特点:用于一些特定的符号来表示一些代码的操作,这样可以简化书写。
- 好处:可以简化对字符串的复杂操作。
- 弊端:符号定义越多,正则越长,阅读性越差。
二、常见符号
- 字符
- 字符类
- 预定义字符类
- 边界匹配符
- Greedy数量词
- 组和捕获
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式((A)(B(C)))中,存在四个这样的组:
((A)(B(C))), \A, (B(C)), (C)
组零始终代表整个表达式。在替换中常用$匹配组的内容。
三、正则表达式的应用
正则表达式主要的功能:匹配、切割、替换和获取。
1. 匹配:String类的boolean matches(String regex)方法。用正则表达式匹配整个字符串,只要一处不符合规则,就匹配结束,返回false。
实例:对QQ号码进行校验
/**
* QQ號碼校驗,要求:5~15位,不能以0開頭,只能是數字
*/
public class QQCheck {
private static String QQ = "127887308";
public static void main(String[] args) {
// 方法一, 不使用正则表达式
traditionCheck(QQ);
// 方法二,使用正则表达式
regexCheck(QQ);
}
/**
* 使用正则表达式匹配QQ号码
*/
private static void regexCheck(String qq) {
String regex = "[1-9]\\d{4,14}"; //[1-9][0-9]{4,14}
if (qq.matches(regex)) {
System.out.println(qq);
} else {
System.out.println(qq + ": 不是正确的QQ号码");
}
}
/**
* 使用传统方法验证QQ号码的正确
*/
private static void traditionCheck(String qq) {
if(!qq.startsWith("0")){
if (qq.length() >= 5 && qq.length() <= 15){
try {
Long l = Long.parseLong(qq);
System.out.println(l);
} catch (NumberFormatException e) {
System.out.println("QQ号码全是数字!");
}
} else {
System.out.println("QQ号码的长度在5到15位之间!");
}
} else {
System.out.println("QQ號碼不能以0開頭!");
}
}
}
2.切割:String类中的String[] split(String regex)方法。
实例:按照空格切割字符串
/**
* 按空格切割含有空格的字符串
*/
public class SpliteLABS {
private static String str1 = "Where there is a will, there is a way";
private static String str2 = "Where there is a will, there is a way";
public static void main(String[] args) {
// 不适用正则表达式
// splitStrByBlack(str1);
// splitStrByTra(str2); // 和str1相比,切割之后产生字符串数组中有很多空字符串。
// 要怎么才能使字符串按空格切割,切割之后的字符串数组中也没有空白字符串?这要用到正则表达式
splitStrByReg(str2);
}
/**
* 按空格切割含有空格的字符串,使用正则表达式
*/
private static void splitStrByReg(String str) {
String regex = " +"; // 可能有一个空格或多个空格
String[] array = str.split(regex);
print(array);
}
/**
* 按空格切割含有空格的字符串,使用传统的方式
*/
private static void splitStrByTra(String str) {
String[] array = str.split(" ");
print(array);
}
private static void print(String[] array) {
for (String str : array) {
System.out.println(str);
}
}
}
在上面的程序中,我们可以切割任意多的空格,但是如果有这么一个字符串“erkktyqqquizzzzzo”让它用“kk”、“qqq”等这样的叠词切割,该怎么实现了,这要用到组,切看下面的代码
/**
* 用正则表达式切割叠词
*/
public class SplitRepeatWord {
private static String str = "erkktyqqquizzzzzo";
public static void main(String[] args) {
String regex = "(.)\\1+"; // 出现两次或者以上的叠词
String[] array = str.split(regex);
for (String str : array) {
System.out.println(str);
}
}
}
按叠词切割,为了让规则重用,将规则封装成组,用()包起来。给组定义编号,想要使用已有的组可通过\n(n是编号)的方式完成。
3.替换:String replaceAll(String regex, String replacement)方法。
示例:
/**
* 使用正则表达式替换
*/
public class ReplaceByRegex {
private static String str = "jaiscasn8q374e9768129ejed08ew2i8e"; // 将字符串中的数字替换成#
private static String str1 = "erkktyqqquizzzzzo"; // 将叠词替换成一个
public static void main(String[] args) {
String regex = "\\d+"; // 数数字,出现1次或者多次
String regex1 = "(.)\\1+"; // 判断叠词
str = str.replaceAll(regex, "#");
System.out.println(str);
str1 = str1.replaceAll(regex1, "$1"); //将叠词替换为一个,其中$1表示符合组中一个字符
System.out.println(str1);
}
}
4.获取:将字符串中符合规则的字串取出
/**
* 将一个字符串中子串长度为4的取出
*/
public class PatternDemo {
private static String str = "Where there is a will, there is a way";
public static void main(String[] args) {
String regex = "\\b[a-z]{4}\\b";
get(str, regex);
}
private static void get(String str2, String regex) {
// 将规则封装成对象
Pattern pattern = Pattern.compile(regex);
// 获取匹配对象
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());//group()方法用于获取匹配后结果。
System.out.println(matcher.start()+"...."+matcher.end()); //start()和end()分别表示匹配字符的开始和结尾的索引
}
}
}
四、练习
- 治口吃
将“我我…我..我要…要…要要….学学….学学学……编编编…程…程程….”转化成:“我要学编程”
/**
* 治口吃
*/
public class TreatmentStuttering {
public static void main(String[] args) {
String str = "我我...我..我要...要...要要....学学....学学学......编编编...程...程程....";
// 先将.号去掉
String regex = "\\.+"; //注意.号可以匹配任意字符,因此不可以写成".+"
str = str.replaceAll(regex, "");
System.out.println(str);
// 将叠词变成一个
String regex1 = "(.)\\1+";
str = str.replaceAll(regex1, "$1");
System.out.println(str);
}
}
2.ip地址进行排序
将下面IP地址排序
192.168.1.254、102.49.23.13、10.10.10.10、2.2.2.2、8.109.89.22
/**
* IP排序
*/
public class IPSort {
public static void main(String[] args) {
String ip = "192.168.1.254 102.49.23.13 10.10.10.10 2.2.2.2 8.109.89.22";
// 补零操作
String regex = "(\\d+)";
ip = ip.replaceAll(regex, "00$1");
// 使每段只保留三位
regex = "0*(\\d{3})";
ip = ip.replaceAll(regex, "$1");
// System.out.println(ip);
// 按空格切割
regex = " +";
String[] array = ip.split(regex);
// 定义TreeSet集合
TreeSet<String> treeSet = new TreeSet<String>();
for (String str : array) {
treeSet.add(str);
}
// 遍历集合,并将每段之前的0去掉
regex = "0*(\\d)";
for (String str : treeSet) {
System.out.println(str.replaceAll(regex, "$1"));
}
}
}
3.对邮箱地址进行校验
public class CkeckMail {
private static String mail = "pegasus153@game.com.cn";
public static void main(String[] args) {
String regex = "\\w+@[a-zA-Z_1-9]+(\\.[a-zA-Z]+){1,3}";
boolean b = mail.matches(regex);
System.out.println(b);
}
}
4.网络爬虫(蜘蛛)
收集网络上的指定信息
/**
* 收集邮箱
*/
public class Spider {
public static void main(String[] args) throws Exception {
getWebMail();
}
private static void getWebMail() throws Exception {
// 封装网页地址
URL url = new URL("http://tieba.baidu.com/p/2314539885");
// 连接服务器
URLConnection connection = url.openConnection();
// 读取
BufferedReader in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line = null;
// 定义匹配邮箱地址的正则
String regex = "\\w+@\\w+(\\.\\w+)+";
Pattern pattern = Pattern.compile(regex);
while ((line = in.readLine()) != null) {
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
}
五、扩展
推荐以后再使用正则表达式,去这些网站获取以及验证:
在线正则表达式测试
正则表达式在线测试 - 站长工具等