
正则表达式,又称规则表达式。(英语:Regular expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表通常被用来检索、替换那些符合某个模式(规则)的文本。
1.1、概念正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
1.2、正则表达式可以做什么给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
其他相关概念
引擎
正则引擎主要可以分为两大类:一种是DFA,一种是NFA。这两种引擎都有了很久的历史(至今二十多年),当中也由这两种引擎产生了很多变体!于是POSIX的出台规避了不必要变体的继续产生。这样一来,主流的正则引擎又分为3类:
一、DFA,二、传统型NFA,三、POSIX NFA。
正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义。【请查阅相关元字符表】
java.util.regex.Pattern
(1)字符串匹配(字符匹配)
(2)字符串查找
(3)字符串替换
例如:
(1)手机号码是否符合规范等
(2)邮箱地址是否正确
(3)IP地址是否正确
java.lang.String
java.util.regex.Pattern
java.util.regex.Matcher
(1)QQ校验
(2)手机号码验证
(3)邮箱地址校验 dsfd@fsd.fds
(4)获取由三个字符组成的单词
public class qq {
public static void main(String[] args) {
// String.matches(String regex);
String regex = "[1-9][0-9]{4,14}";//正则表达式
boolean b = "204227136".matches(regex);
System.out.println(204227136+" : "+b);
}
// 需求:定义一个功能对QQ号进行校验
// 要求:长度5-15,只能是数字,0不能开头
public static void checkQQ(String qq) {
int len = qq.length();
if (len >= 5 && len <= 15) {
if (!qq.startsWith("0")) {
try {
long l = Long.parseLong(qq);
System.out.println(l + " 正确!");
} catch (NumberFormatException e) {
System.out.println(qq + ":含有非法字符!");
}
} else {
System.out.println(qq + " : 不能以0开头");
}
}else{
System.out.println(qq+" 长度错误!");
}
}
}
| 正则表达式(常见的规则) | 可查看JDK API 文档 |
|---|---|
| 字符类 | |
| [abc] | a、b 或 c(简单类) (某一位上只能是a,b,c) |
| [^abc] | 任何字符,除了 a、b 或 c(否定) |
| [a-zA-Z] | a 到 z 或 A 到 Z,两头的字母包括在内(范围) |
| [a-d[m-p]] | a 到 d 或 m 到 p:[a-dm-p](并集) |
| [a-z&&[def]] | d、e 或 f(交集) |
| [a-z&&[^bc]] | a 到 z,除了 b 和 c:[ad-z](减去) |
| [a-z&&[^m-p]] | a 到 z,而非 m 到 p:[a-lq-z](减去) |
| 预定义字符类 | |
| . | 任何字符(与行结束符可能匹配也可能不匹配) |
| d | 数字:[0-9] |
| D | 非数字: [^0-9] |
| s | 空白字符:[ tnx0Bfr] |
| S | 非空白字符:[^s] |
| w | 单词字符:[a-zA-Z_0-9] |
| W | 非单词字符:[^w] |
| 边界匹配器 | |
| ^ | 行的开头 |
| $ | 行的结尾 |
| b | 单词边界 |
| B非单词边界 | |
| A | 输入的开头 |
| G | 上一个匹配的结尾 |
| Z | 输入的结尾,仅用于最后的结束符(如果有的话) |
| z | 输入的结尾 |
| Greedy 数量词 | |
| X? | X,一次或一次也没有 (举例演示) |
| X* | X,零次或多次 |
| X+ | X,一次或多次 |
| X{n} | X,恰好 n 次 |
| X{n,} | X,至少 n 次 |
| X{n,m} | X,至少 n 次,但是不超过 m 次 |
public class RegexDemo2 {
public static void main(String[] args) {
String str ="aooooooooooooooooooooooooooob";
//String reg = "ao?b";
//String reg = "ao{4}b";
//String reg = "ao{4,}b";
//String reg = "ao{4,6}b";
//String reg = "ao+b";
String reg = "ao*b";
boolean b = str.matches(reg);
System.out.println(b);
}
}
2.3、案例3
需求:手机号码验证(必讲)
正则表达式对字符串的常见操作:
1、匹配
其实使用的就是String类中的matches()方法
2、切割
其实使用的就是String类中的split()方法
3、替换
其实使用的就是String类中的replaceAll()方法
4、获取
public class RegexDemo3 {
public static void main(String[] args) {
// method1();
// method2();
method3();
// method4();
}
public static void method1() {
String tel = "15804901111";
String regex = "1[358][0-9]{9}";
// String regex = "1[358]\d{9}";
boolean b = tel.matches(regex);
System.out.println(tel + " : " + b);
}
public static void method2() {
String str1 = "zhangsan xiaoqiang zhaoliu";
// String str2 = "zhangsan.xiaoqiang.zhaoliu";
// String str3 = "zhangsanttttxiaoqiangmmmmmmzhaoliu";//组
String[] names = str1.split(" ");
// String [] names = str1.split(" +");
// String [] names = str2.split("\.");
// String [] names = str3.split("(.)\1+");//组
for (String name : names) {
System.out.println(name);
}
}
public static void method3() {
String str = "zhangsanttttxiaoqiangmmmmmmzhaoliu";
str = str.replaceAll("(.)\1+", "$1");//
System.out.println(str);
String tel = "15856567788";
tel = tel.replaceAll("(\d{3})\d{4}(\d{4})", "$1****$2");
System.out.println(tel);
}
public static void method4(){
String str = "da jia hao,ming tian bu fang jia";
//String regex = "[a-z]{3}";
String regex = "\b[a-z]{3}\b";// 单词边界 \b
//1、将正则规则进行对象的封装
Pattern p = Pattern.compile(regex);
//2、通过正则对象获取匹配器对象
Matcher m = p.matcher(str);
//3、使用Matcher对象的方法对字符串进行操作。
// 既然要获取三个字母组成的单词
// 查找find();
// m.find();
// System.err.println(m.group());//获取匹配的子序列
System.out.println(str);
while(m.find()){
System.out.println(m.group());//获取匹配的子序列
System.out.println(m.start()+" : "+m.end());
}
}
}
注意:(.)1+
"(.+)(.*?)\1"表示什么意思呢? .表示单个字符+表示一个或多个, .+表示一个或多个单字符。 ()是什么意思呢? 举个例子 ( a.)+ 表示一个或多个a.此处.表示字符 a(.+)表示a一个或多个. 区别在于第一个表示的a和.数量是相同的 第二行只有一个a 所以()的意思就是限定+修饰的字符 (.*?)表示任意多个单字符(包括没有) 这个?是什么意思呢?表示最小的匹配 \1表示第一个括号中匹配到的字符 字符串a2a2a2中"(.+)(.*?)\1" 改变后为a2a2 即$1匹配和\1是相同的只能是a2 $2就匹配为中间的a2 若字符串为1111则$1和\1匹配的就是11和11$2匹配到的就是空的 $1$2分别表示第一个()和第二个()匹配的值2.4、案例4需求1:治疗口吃:我我…我我…我要…要要要要…要要要要…学学学学…编编编编编…程程
需求2:对ip地址排序
需求3:对邮件地址校验
import java.util.Arrays;
import java.util.TreeSet;
public class RegexTest { public static void main(String[] args) { // test1(); test2(); // test3(); } public static void test1() { String str = "我我...我我...我要...要要要要...要要要要...学学学学学...编编编编编....程程程程"; // 1.将字符串中.去掉。用替换 str = str.replaceAll("\.+", ""); System.out.println(str); // 2.替换叠词 str = str.replaceAll("(.)\1+", "$1"); System.out.println(str); } public static void test2() { String ipstr = "192.168.10.55 127.0.0.1 3.3.3.3 105.7.11.65"; // 方式二 // 1.为了让ip可以按照字符串顺序比较,只要让ip的每一段的位数相同。 // 所以,补零,按照每一位所需做多0进行补充,每一段都加两个0. ipstr = ipstr.replaceAll("(\d+)", "00$1"); System.out.println(ipstr); //00192.00168.0010.0055 00127.000.000.001 003.003.003.003 00105.007.0011.0065 // 然后每一段保留数字3位 ipstr = ipstr.replaceAll("0*(\d{3})", "$1"); System.out.println(ipstr); // 方式一 // 1.将ip地址切出 String[] ips = ipstr.split(" +"); TreeSet2.5、案例5ts = new TreeSet (); // Arrays.sort(ips); for (String ip : ips) { System.out.println(ip); ts.add(ip); } for (String ip : ts) { System.out.println(ip); System.out.println("---"+ip.replaceAll("0*(\d+)", "$1")); } } public static void test3(){ String mail = "abc1@sina.com"; String regex = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\.[a-zA-Z]{1,3})+"; //regex = "\w+@\w+(\.\w+)+";// 1@1.1 boolean b = mail.matches(regex); System.out.println(mail+" : "+b); } } 需求:爬虫 (需要自做一个静态的网页包含邮箱地址)-- (看情况讲解/代码直接讲解演示)
网页爬虫:其实就是一个程序用于在互联网中获取符合指定规则的数据。 爬取邮箱地址版本一:本地版 – mail.html放在本地硬盘目录即可
版本二:网络版 – mail.html 部署在tomcat中 演示 模拟网络获取网页中的邮箱地址
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest2 { public static void main(String[] args) throws IOException { List2.6、案例6list = getMails(); for (String mail : list) { System.out.println(mail); } } public static List getMails() throws IOException { List list = new ArrayList (); // 1.读取源文件 BufferedReader br = new BufferedReader(new FileReader("c:\mail.html")); // 2.对读取的数据进行规则的匹配。从中获取符合规则的数据。 String mailRegex = "\w+@\w+(\.\w+)+"; Pattern p = Pattern.compile(mailRegex); String line = null; while ((line = br.readLine()) != null) { Matcher m = p.matcher(line); while (m.find()) { // 3.将符合规则的数据存储到集合中 list.add(m.group()); } } return list; } public static List getMailsByweb() throws IOException { List list = new ArrayList (); // 1.读取源文件 //BufferedReader br = new BufferedReader(new FileReader("c:\mail.html")); URL url = new URL("http://12.168.1.100:8080/myweb/mail.html"); //URL url = new URL("http://renshi.nwpu.edu.cn/rczp/index.html"); URL url = new URL("http://www.lhtit.com/Contactus/index.html"); BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream())); // 2.对读取的数据进行规则的匹配。从中获取符合规则的数据。 String mailRegex = "\w+@\w+(\.\w+)+"; Pattern p = Pattern.compile(mailRegex); String line = null; while ((line = br.readLine()) != null) { Matcher m = p.matcher(line); while (m.find()) { // 3.将符合规则的数据存储到集合中 list.add(m.group()); } } return list; } } 需求:统计java文件中的 空行 代码行 注释 数量 (看情况讲解/代码直接讲解演示)
package com.sxt.javaregex.demo;import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class CodeCounter { static long normalLines = 0;//正常行 static long commentLines = 0;//注释行 static long whiteLines = 0;//空白行 public static void main(String[] args) { //1.获得文件夹 File f = new File("C:\javacode"); //2.获得子文件夹中的 java文件 File[] codeFiles = f.listFiles(); for(File child : codeFiles){ if(child.getName().matches(".*\.java$")) {// $代表结尾 parse(child); } } System.out.println("normalLines:" + normalLines); System.out.println("commentLines:" + commentLines); System.out.println("whiteLines:" + whiteLines); } private static void parse(File f) { BufferedReader br = null; boolean comment = false; try { br = new BufferedReader(new FileReader(f)); String line = ""; while((line = br.readLine()) != null) { line = line.trim();//去掉 注释前的 tab换行 if(line.matches("^[\s&&[^\n]]*$")) {//匹配空白行 whiteLines ++; } else if (line.startsWith("")) {//匹配注释开始 commentLines ++; comment = true; } else if (line.startsWith("")) { commentLines ++; } else if (true == comment) { commentLines ++; if(line.endsWith("*/")) {//匹配注释结束 comment = false; } } else if (line.startsWith("//")) { commentLines ++;//匹配单行注释 } else { normalLines ++; } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(br != null) { try { br.close(); br = null; } catch (IOException e) { e.printStackTrace(); } } } } }总结
正则表达式 不要刻意去记 要理解