一、正则表达式介绍:
1、什么是正则表达式?
符合一定(判断/校验)规则的表达式。
2、作用:专门用于处理字符串的。
3、好处:可以简化对字符串的复杂操作。
4、弊端:符号定义越多,正则越长,阅读性越差。
5、特点:用一些特定的符号来表示一些代码操作,这样就简化了书写。(所以学习正则表达式,就是在学习一些特殊符号的使用)
6、正则表达式的构造摘要:
构造 | 匹配 |
字符 | |
x | 字符x |
\\ | 反斜线字符 |
\0n | 带有八进制值 0 的字符 n (0 <= n <= 7) |
\0nn | 带有八进制值 0 的字符 nn (0 <= n <= 7) |
\0mnn | 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7) |
\xhh | 带有十六进制值 0x 的字符 hh |
\uhhhh | 带有十六进制值 0x 的字符 hhhh |
\t | 制表符 ('\u0009') |
\n | 新行(换行)符 ('\u000A') |
\r | 回车符 ('\u000D') |
\f | 换页符 ('\u000C') |
\a | 报警 (bell) 符 ('\u0007') |
\e | 转义符 ('\u001B') |
\cx | 对应于 x 的控制符 |
字符类 | |
[abc] | 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 | 空白字符:[ \t\n\x0B\f\r] |
\S | 非空白字符:[^\s] |
\w | 单词字符:[a-zA-Z_0-9] |
\W | 非单词字符:[^\w] |
POSIX 字符类(仅 US-ASCII) | |
\p{Lower} | 小写字母字符:[a-z] |
\p{Upper} | 大写字母字符:[A-Z] |
\p{ASCII} | 所有 ASCII:[\x00-\x7F] |
\p{Alpha} | 字母字符:[\p{Lower}\p{Upper}] |
\p{Digit} | 十进制数字:[0-9] |
\p{Alnum} | 字母数字字符:[\p{Alpha}\p{Digit}] |
\p{Punct} | 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ |
\p{Graph} | 可见字符:[\p{Alnum}\p{Punct}] |
\p{Print} | 可打印字符:[\p{Graph}\x20] |
\p{Blank} | 空格或制表符:[ \t] |
\p{Cntrl} | 控制字符:[\x00-\x1F\x7F] |
\p{XDigit} | 十六进制数字:[0-9a-fA-F] |
\p{Space} | 空白字符:[ \t\n\x0B\f\r] |
java.lang.Character 类(简单的 java 字符类型) | |
\p{javaLowerCase} | 等效于 java.lang.Character.isLowerCase() |
\p{javaUpperCase} | 等效于 java.lang.Character.isUpperCase() |
\p{javaWhitespace} | 等效于 java.lang.Character.isWhitespace() |
\p{javaMirrored} | 等效于 java.lang.Character.isMirrored() |
Unicode 块和类别的类 | |
\p{InGreek} | Greek块(简单块)中的字符 |
\p{Lu} | 大写字母(简单类别) |
\p{Sc} | 货币符号 |
\P{InGreek} | 所有字符,Greek 块中的除外(否定) |
[\p{L}&&[^\p{Lu}]] | 所有字母,大写字母除外(减去) |
边界匹配器 | |
^ | 行的开头 |
$ | 行的结尾 |
\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 次 |
Reluctant 数量词 | |
X?? | X,一次或一次也没有 |
X*? | X,零次或多次 |
X+? | X,一次或多次 |
X{n}? | X,恰好 n 次 |
X{n,}? | X,至少 n 次 |
X{n,m}? | X,至少 n 次,但是不超过 m 次 |
Possessive 数量词 | |
X?+ | X,一次或一次也没有 |
X*+ | X,零次或多次 |
X++ | X,一次或多次 |
X{n}+ | X,恰好 n 次 |
X{n,}+ | X,至少 n 次 |
X{n,m}+ | X,至少 n 次,但是不超过 m 次 |
Logical 运算符 | |
XY | X 后跟 Y |
X|Y | X 或 Y |
(X) | X,作为捕获组 |
Back 引用 | |
\n | 任何匹配的 nth 捕获组 |
引用 | |
\ | Nothing,但是引用以下字符 |
\Q | Nothing,但是引用所有字符,直到 \E |
\E | Nothing,但是结束从 \Q 开始的引用 |
特殊构造(非捕获) | |
(?:X) | X,作为非捕获组 |
(?idmsux-idmsux) | |
(?idmsux-idmsux:X) | |
(?=X) | X,通过零宽度的正 lookahead |
(?!X) | X,通过零宽度的负 lookahead |
(?<=X) | X,通过零宽度的正 lookbehind |
(?<!X) | X,通过零宽度的负 lookbehind |
(?>X) | X,作为独立的非捕获组 |
二、正则表达式和字符串的集合应用:
①、匹配:boolean matches(String regex);用规则匹配整个字符串,只要有一处不符合规则,就匹配结束,返回false。
②、切割:String[] split(String regex); 通过规则来切割字符串,使用字符串数组接收。
③、替换:String replaceAll(String regex,String str); 如果regex中有定义组,可以在第二参数中通过$符号获取正则表达式中的已有的组。
④、获取:将字符串中的符合规则的子串取出。
操作步骤:
1) 将正则表达式封装成对象。
2) 让正则对象和要操作的字符串相关联。
3) 关联后,获取正则匹配引擎。
4) 通过引擎对符合规则的子串进行操作,比如取出。
匹配:不使用正则表达式校验字符串的操作示例
/*
需求:对QQ号码进行校验。
要求:
①、位数:5~15位
②、0不能开头
③、只能由数字组成。
第一种实现方式:判断语句 + String类中方法
*/
class RegexDemo
{
public static void main(String[] args)
{
checkQQ();
}
public static void checkQQ()
{
String qq = "123a8845"; //定义输入的QQ号。
int len = qq.length(); //定义变量用于表示QQ号的长度。
if(len>=5 && len<=15) //定义判断条件,用于判断QQ号的长度。
{
if(!qq.startsWith("0")) //判断QQ号是否是0开头。
{
char[] arr = qq.toCharArray();
boolean flag = true;
for(int x=0; x<arr.length; x++)
{
if(!(arr[x]>='0' && arr[x]<='9')) //判断QQ号是否都是由数字组成。
{
flag = false;
break;
}
}
if(flag)
{
System.out.println("qq:"+qq);
}
else
{
System.out.println("输入的QQ号出现非法字符");
}
}
else
{
System.out.println("QQ号不可以0开头");
}
}
else
{
System.out.println("QQ号长度错误");
}
}
}
总结:以上方式使用了String类中的方法进行组合,虽然完成了需求,但是代码却过于复杂。
/*
第二种实现方式:正则表达式
*/
class Regex
{
public static void main(String[] args)
{
checkQQ();
}
public static void checkQQ()
{
String qq = "1238845"; //定义输入的QQ号。
String regex = "[1-9][0-9]{4,14}"; //定义QQ号校验规则。[1-9]表示第一个位置是1到9之间的数字,也就是开头不为0。[0-9]表示第二个位置是0到9之间的数字。{4,14}表示除了第一个位置的数字不为0之外,其它位置上都是0到9之间的数字。
boolean flag = qq.matches(regex); //使用String类中的matches方法去匹配校验规则,返回一个boolean类型的值,根据这个值的结果来判断输入的QQ号是否符合要求。
if(flag)
System.out.println(qq+"...isok");
else
System.out.println(qq+"......不合法");}
}
切割:使用正则表达式定义的规则来切割字符串
代码示例:
class RegexDemo
{
public static void main(String[] args)
{
splitDemo("zhangsan.lisi.wangwu","\\."); //使用一个点来切割。
splitDemo("c:\\abc\\a.txt","\\\\"); //使用双斜杠来切割。
splitDemo("erkktyqqquizzzzzo","(.)\\1+"); //按照叠词完成切割。
//为了可以让规则结果被重用,可以将规则封装成一个组,用小括号()完成。
//组的出现都有编号,从1开始。
//想要使用已有的组,可以通过\n(n就是组的编号)的形式来获取。
//((())()) 这里是4个组。通过有多少个左括号就判断出有多少个组。从左往右数。
}
public static void splitDemo(String str,String reg)
{
String[] arr = str.split(reg);
System.out.println(arr.length);
for(String s : arr)
{
System.out.println(s);
}
}
}
替换:使用指定的字符串替换匹配正则规则的字符串
代码示例:
class RegexDemo
{
public static void main(String[] args)
{
String str = "wer1389980000ty1234564uiod234345675f";
replaceAllDemo(str,"\\d{5,}","#"); //将字符串中的数字替换成#。
Stringstr1 = "erkktyqqquizzzzzo";
replaceAllDemo(str1,"(.)\\1+","&"); //将叠词替换成&
replaceAllDemo(str1,"(.)\\1+","$1"); //将重叠的字符替换成单个字母。zzzz->z
}
public static void replaceAllDemo(String str,String reg,String newStr)
{
str = str.replaceAll(reg,newStr);
System.out.println(str);
}
}
获取:将字符串中的符合规则的子串取出。
代码示例:
import java.util.regex.*;
class RegexDemo2
{
public static void main(String[] args)
{
getDemo();
}
public static void getDemo()
{
String str = "ming tian jiu yao fang jia le ,da jia";
System.out.println(str);
String reg = "\\b[a-z]{4}\\b";
//1、将规则封装成对象。
Pattern p = Pattern.compile(reg);
//2、让正则对象和要作用的字符串相关联,通过matcher方法。
//3、获取匹配器对象m
Matcher m = p.matcher(str);
//System.out.println(m.matches()); //其实String类中的matches方法。用的就是Pattern和Matcher对象来完成的。
//只不过被String的方法封装后,用起来较为简单。但是功能却单一。
//boolean b = m.find(); //将规则作用到字符串上,并进行符合规则的子串查找。
while(m.find())
{
System.out.println(m.group()); //通过循环,用于获取匹配后的结果。
System.out.println(m.start()+"...."+m.end());
}
}
}
***正则表达式演示——“网页爬虫”
需求:通过定义正则表达式程序获取指定文件或者网页中的邮箱地址。
import java.util.regex.*;
import java.io.*;
import java.net.*;
class RegexTest2
{
public static void main(String[] args) throws Exception
{
getMails();
getMails_1();
}
public static void getMails_1() throws Exception
{
//通过正则表达式匹配规则获取指定web页面上的邮箱地址。
URL url = new URL("http://192.168.1.88:8080/myweb/mail.html");
URLConnection conn = url.openConnection();
BufferedReader bufIn = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;
//定义邮箱地址匹配规则。
String mailreg = "\\w+@\\w+(\\.\\w+)+";
Pattern p = Pattern.compile(mailreg);
while((line = bufIn.readLine()) != null)
{
Matcher m = p.matcher(line);
while(m.find())
{
System.out.println(m.group());
}
}
}
/*
获取指定文档中的邮件地址。
使用获取功能。Pattern Matcher
*/
public static void getMails() throws Exception
{
BufferedReader bufr = new BufferedReader(new FileReader("mail.txt"));
String line = null;
//定义邮箱地址匹配规则。
String mailreg = "\\w+@\\w+(\\.\\w+)+";
Pattern p = Pattern.compile(mailreg);
while((line = bufr.readLine()) != null)
{
Matcher m = p.matcher(line);
while(m.find())
{
System.out.println(m.group());
}
}
}
}