一、正则表达式概述
1.定义
正则表达式:是符合一定规则的表达式,是一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在很多文本编辑器或其他工具里,正则表达式通常被用来检索和/或替换那些符合某个模式的文本内容。
在java中主要操作字符串,API路径java.util.regex.Pattern
2.特点
(1)用于一些特定的符号来表示一些代码操作,这样可以简化书写。所以学习正则表达式,就是在学习一些特殊符号的使用。
(2)灵活性、逻辑性和功能性非常的强。
3.优缺点
好处:可以简化对字符串的复杂操作。
弊端:符号定义越多,阅读困难,表达式越长,阅读性越差。
二、正则表达式的构造摘要
构造 匹配
字符
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) Nothing,但是将匹配标志i d m s u x on - off
(?idmsux-idmsux:X) X,作为带有给定标志 i d m s u x on - off
(?=X) X,通过零宽度的正 lookahead
(?!X) X,通过零宽度的负 lookahead
(?<=X) X,通过零宽度的正 lookbehind
(?<!X) X,通过零宽度的负 lookbehind
(?>X) X,作为独立的非捕获组
三、正则表达式常见应用
通过Pattern中的方法,使用正则表达式构造的符号来表示一些代码,从而达到字符串处理,表单验证的效果。
1.匹配
使用方法:matches()
匹配原则:用规则匹配整个字符串,只要有一处不符合规则,就匹配结束,返回false。
比如:boolean flag = str.matches(reg);
示例1:验证一串数字是否为电话号码
class CheckTel
{
public static void main(String[] args)
{
String tel = "16900001111";//待验证的号码
String telReg = "1[358]\\d{9}";//匹配规则:第一位为1,第二位为3、5或8,后9位为数字
System.out.println(tel.matches(telReg));//结果false,不匹配
}
}
2.切割
使用方法:split();围绕此模式的匹配拆分给定输入序列
例如:String arr[] = str split(reg);
示例:
class RegexDemo
{
public static void main(String[] args)
{
splitDemo("zhangsan.lisi.wangwu","\\.");//以字符串中的“.”为标记进行切割
splitDemo("c:\\abc\\a.txt","\\\\");//以字符串中的“\\”为标记进行切割
splitDemo("erkktyqqquizzzzzo","(.)\\1+");//按照叠词完成切割
}
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);
}
}
}
注 意:(1)切割时,\为转意符,使用\切割时,要写\\,否则会将\后边的引号转意。
(2).代表所有类型,使用它切割时,要进行转意,如“\\.”。
(3)按照叠词完成切割时,为了可以让规则的结果被重用,可以将规则封装成一个组,用()完成。组的出现都有编号,从1开始。想要使用已有的组可以通过\n(n就是组的编号)的形式来获取。
3.替换
使用方法:String replaceAll();使用新字符串替换符合规则的字符串
例如:str = str.replaceAll(reg,new str);
示例:
class RegexDemo
{
public static void main(String[] args)
{
String str = "wer1389980000ty1234564uiod234345675f";//将字符串中的数组替换成#。
replaceAllDemo(str,"\\d{5,}","#");
String str1 = "erkktyqqquizzzzzo";//将重叠的字符替换成单个字母,zzzz->z.
replaceAllDemo(str1,"(.)\\1+","$1");
}
public static void replaceAllDemo(String str,String reg,String newStr)
{
str = str.replaceAll(reg,newStr);
System.out.println(str);
}
}
注意:$可以代表规则里出现的字符,如示例里会随着重叠的字符的变化而变化。
4.获取
将字符串上符合规则的子串取出。
操作步骤:
(1)将正则表达式封装成对象。如:Pattern p = Pattern.compile(reg);
(2)让正则对象和要操作的字符串相关联。
(3)关联后,获取正则匹配引擎。如:Matcher m = p.matcher(str);
(4)通过引擎对符合规则的子串进行操作,比如取出。
示例1:获取字符串中四个字母的单词
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。";
String reg = "\\b[a-z]{4}\\b";//规则:连续四个字母的子串
//将规则封装成对象。
Pattern p = Pattern.compile(reg);
//让正则对象和要作用的字符串相关联。获取匹配器对象。
Matcher m = p.matcher(str);
//其实String类中的matches方法。用的就是Pattern和Matcher对象来完成的。
//只不过被String的方法封装后,用起来较为简单。但是功能却单一。
//将规则作用到字符串上,并进行符合规则的子串查找。
while(m.find())
{
System.out.println(m.group());//用于获取匹配后结果。
System.out.println(m.start()+"...."+m.end());
}
}
}
四、基础加强: 正则表达式的综合应用
将"我我...我我...我要..要要...要要...学学学....学学...编编编...编程..程.程程...程...程"转成"我要学编程"。到底用四种功能中的哪一个或者哪几个呢?
思路方式:
(1)如果只想知道该字符是否对是错,使用匹配。
(2)想要将已有的字符串变成另一个字符串,替换。
(3)想要按照自定的方式将字符串变成多个字符串,切割,获取规则以外的子串。
(4)想要拿到符合需求的字符串子串,获取符合规则的子串。
代码如下:
import java.util.*;
class RegexTest
{
public static void main(String[] args)
{
String str = "我我...我我...我要..要要...要要...学学学....学学...编编编...编程..程.程程...程...程";
/*
将已有字符串变成另一个字符串。使用替换功能。
1.可以先将 . 去掉。
2.在将多个重复的内容变成单个内容。
*/
str = str.replaceAll("\\.+","");//将.替换成空字符串,即去除.
//System.out.println(str);打印去掉.后的字符串
str = str.replaceAll("(.)\\1+","$1");//将重复的字符串变成单个
System.out.println(str);
}