一、 什么是正则表达式
正则表达式是由普通字符(如英文字母)以及特殊字符(也称为元字符)组成的文字模式。该模式对文本查找时需要匹配的一个或多个字符串描述,给出一个匹配模板。
二、为什么要使用正则表达式
正则表达式可以大大简化文本识别工作,现已超出了某种语言或某个系统的局限,成为被人们广为使用的工具。
三、正则表达式简介
1. 正则表达式基本书写符号
符号
符号
示例
解释
匹配输入
\
转义符
\*
符号“*”
*
[ ]
可接收的字符列表
[efgh]
e、f、g、h中的任意1个字符
e、f、g、h
[^]
不接收的字符列表
[^abc]
除a、b、c之外的任意1个字符,包括数字和特殊符号
m、q、5、*
|
匹配“|”之前或之后的表达式
ab|cd
ab或者cd
ab、cd
( )
将子表达式分组
(abc)
将字符串abc作为一组
abc
-
连字符
A-Z
任意单个大写字母
大写字母
2.正则表达式限定符
限定符将可选数量的数据添加到正则表达式,下表为常用限定符:
符号
含义
示例
示例
匹配输入
不匹配输入
*
指定字符重复0次或n次
(abc)*
仅包含任意个abc的字符串,等效于\w*
abc、abcabcabc
a、abca
+
指定字符重复1次或n次
m+(abc)*
以至少1个m开头,后接任意个abc的字符串
m、mabc、mabcabc
ma、abc
?
指定字符重复0次或1次
m+abc?
以至少1个m开头,后接ab或abc的字符串
mab、mabc、mmmab、mmabc
ab、abc、mabcc
{n}
只能输入n个字符
[abcd]{3}
由abcd中字母组成的任意长度为3的字符串
abc、dbc、adc
a、aa、dcbd
{n,}
指定至少 n 个匹配
[abcd]{3,}
由abcd中字母组成的任意长度不小于3的字符串
aab、dbc、aaabdc
a、cd、bb
{n,m}
指定至少 n 个但不多于 m 个匹配
[abcd]{3,5}
由abcd中字母组成的任意长度不小于3,不大于5的字符串
abc、abcd、aaaaa、bcdab
ab、ababab、a
^
指定起始字符
^[0-9]+[a-z]*
以至少1个数字开头,后接任意个小写字母的字符串
123、6aa、555edf
abc、aaa、a33
$
指定结束字符
^[0-9]\-[a-z]+$
以1个数字开头后接连字符“–”,并以至少1个小写字母结尾的字符串
2-a、3-ddd、5-efg
33a、8-、7-Ab
3. 匹配字符集
匹配字符集是预定义的用于正则表达式中的符号集。如果字符串与字符集中的任何一个字符相匹配,它就会找到这个匹配项。
正则表达式中的部分匹配字符集:
符号
含义
示例
示例
匹配输入
不匹配输入
.
匹配除 \n 以外的任何字符
a..b
以a开头,b结尾,中间包括2个任意字符的长度为4的字符串
aaab、aefb、a35b、a#*b
ab、aaaa、a347b
\d
匹配单个数字字符,相当于[0-9]
\d{3}(\d)?
包含3个或4个数字的字符串
123、9876
123、9876
\D
匹配单个非数字字符,相当于[^0-9]
\D(\d)*
以单个非数字字符开头,后接任意个数字字符串
a、A342
aa、AA78、1234
\w
匹配单个数字、大小写字母字符,相当于[0-9a-zA-Z]
\d{3}\w{4}
以3个数字字符开头的长度为7的数字字母字符串
234abcd、12345Pe
58a、Ra46
\W
匹配单个非数字、大小写字母字符,相当于[^0-9a-zA-Z]
\W+\d{2}
以至少1个非数字字母字符开头,2个数字字符结尾的字符串
#29、#?@10
23、#?@100
4. 分组构造
常用分组构造形式:
常用分组构造形式
说明
()
非命名捕获。捕获匹配的子字符串(或非捕获组)。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号。
(?<name>)
命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如 (?'name')
5.字符转义
如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用\.和\*。当然,要查找\本身,你也得用\\
例如:deerchao\.net匹配deerchao.NET,C:\\Windows匹配C:\Windows。
在Java中的写法: (https://github\\.com/[\\w\\-]) 用"\\."配备"."。
6. 正则表达式举例
◆ 非负整数:“^\d+$ ”
◆ 正整数: “ ^[0-9]*[1-9][0-9]*$”
◆ 非正整数: “ ^((-\d+)|(0+))$”
◆ 整数: “ ^-?\d+$”
◆ 英文字符串: “ ^[A-Za-z]+$”
◆ 英文字符数字串: “ ^[A-Za-z0-9]+$”
◆ 英数字加下划线串: “^\w+$”
◆ E-mail地址:“^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$”
◆ URL:“^[a-zA-Z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\s*)?$”
四、总结
1、字母:匹配单个字母
(1)A:表示匹配字母A;
(2)\\:匹配转义字符“\”;
(3)\t:匹配转义字符“\t”;
(4)\n:匹配转义字符“\n”;
2、一组字符:任意匹配里面的一个单个字符:
(1)[abc]:表示可能是字母a,可能是字母b或者是字母c;
(2)[^abc]:表示不是字母a,字母b,字母c的任意一个;
(3)[a-zA-Z]:表示全部字母中的任意一个;
(4)[0-9]:表示全部数字的任意一个;
3、边界匹配:在以后编写JavaScript的时候使用正则中要使用到:
(1)^:表示一组正则的开始;
(2)$:表示一组正则的结束;
4、简写表达式:每一位出现的简写标记也只表示一位:
(1)· :表示任意的一位字符;
(2)\d :表示任意的一位数字,等价于“[0-9]”;
(3)\D :表示任意的一位非数字,等价于“[~0-9]”;
(4)\w :表示任意的一位字母、数字、_,等价于“[a-zA-Z0-9_]”;
(5)\w :表示任意的一位非字母、数字、_,等价于“[^a-zA-Z0-9_]”;
(6)\s :表示任意的一位空格,例如:\n、\t等;
(7)\S :表示任意的一位非空格;
5、数量表示:之前所有的正则都只是表示一位,如果要表示多位,则就需要数量表示。
(1)正则表达式?:此正则出现0次或1次;
(2)正则表达式*:此正则出现0次、1次或多次;
(3)正则表达式+:次正则出现1次或多次;
(4)正则表达式{n}:此正则出现正好n次;
(5)正则表达式{n,}:此正则出现n次以上;
(6)正则表达式{n,m}:此正则出现n – m次。
6、逻辑表示:与、或、非
(1)正则表达式A正则表达式B: 表达式A之后紧跟着表达式B;
(2)正则表达式|A正则表达式B: 表示表达式A或者表达式B,二者任选一个出现;
(3)(正则表达式):将多个子表达式合成一个表示,作为一组出现。
五、示例
1.验证是否为数字:是否带小数点、正负都行
String str="234234.88";
String rex="-*\\d+\\.*\\d*";
System.out.println(str.matches(rex));
2.假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式。在正则表达式中,连字符(“-”)有着特殊的意义,它表示一个范围,比如从0到9。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“\”。
看看下面那一行正则表达式是对的:
(0-9){3} \-(0-9){2} \- (0-9){4}
[0-9]{3} \-[0-9]{2} \- [0-9]{4}
正确的是:
图:匹配所有123-12-1234形式的社会安全号码
3.假设进行搜索的时候,你希望连字符号可以出现,也可以不出现——即,999-99-9999和999999999都属于正确的格式。这时,你可以在连字符号后面加上一个数量限定符号,如图所示:
看看下面那一行正则表达式是对的:
(0-9){3} \-?(0-9){2} \-? (0-9){4}
[0-9]{3} \-*[0-9]{2} \-* [0-9]{4}
正确的是:
图:匹配所有123-12-1234和123121234形式的社会安全号码
4.美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分“[0-9]{4}”,再加上字母部分“[A-Z]{2}”。图显示了完整的正则表达式。
图:匹配典型的美国汽车牌照号码,如8836KV
5."否"符号
"^"符号称为“否”符号。如果用在方括号内,“^”表示不想要匹配的字符。例如,图四的正则表达式匹配所有单词,但以“X”字母开头的单词除外。
图:匹配所有单词,但“X”开头的除外
6.圆括号和空白符号
假设要从格式为“June 26, 1951”的生日日期中提取出月份部分,用来匹配该日期的正则表达式可以如图所示:
看看下面哪一个是正确的:
[a-z]* \s+ [0-9]{1,2},\s* [0-9]{4}
[a-z]+ \s+ [0-9]{1,2},\s* [0-9]{4}
正确的是:
图:匹配所有Moth DD,YYYY格式的日期
“\s”符号是空白符号,匹配所有的空白字符,包括Tab字符。如果字符串正确匹配,接下来如何提取出月份部分呢?只需在月份周围加上一个圆括号创建一个组
图:匹配所有Month DD,YYYY格式的日期,定义月份值为第一个组
六、JAVA正则表达式Pattern和Matcher
java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。
1.简介:
java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。
它包括两个类:Pattern和Matcher 。
Pattern: 一个Pattern是一个正则表达式经编译后的表现模式。
Matcher:一个Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符串展开匹配检查。
首先一个Pattern实例订制了一个所用语法与PERL的类似的正则表达式经编译后的模式,然后一个Matcher实例在这个给定的Pattern实例的模式控制下进行字符串的匹配工作。
以下我们就分别来看看这两个类:
2.Pattern类:
Pattern的方法如下:
static Pattern compile(String regex)
将给定的正则表达式编译并赋予给Pattern类
static Pattern compile(String regex, int flags)
同上,但增加flag参数的指定,可选的flag参数包括:CASE INSENSITIVE,MULTILINE,DOTALL,UNICODE CASE, CANON EQ
int flags()
返回当前Pattern的匹配flag参数
Matcher matcher(CharSequence input)
生成一个给定命名的Matcher对象
static boolean matches(String regex, CharSequence input)
编译给定的正则表达式并且对输入的字串以该正则表达式为模开展匹配,该方法适合于该正则表达式只会使用一次的情况,也就是只进行一次匹配工作,因为这种情况下并不需要生 成一个Matcher实例。
String pattern()
返回该Patter对象所编译的正则表达式。
String[] split(CharSequence input)
将目标字符串按照Pattern里所包含的正则表达式为模进行分割。
String[] split(CharSequence input, int limit)
作用同上,增加参数limit目的在于要指定分割的段数,如将limi设为2,那么目标字符串将根据正则表达式分为割为两段。
一个正则表达式,也就是一串有特定意义的字符,必须首先要编译成为一个Pattern类的实例,这个Pattern对象将会使用matcher()方法来生成一个Matcher实例,接着便可以使用该 Matcher实例以编译的正则表达式为基础对目标字符串进行匹配工作,多个Matcher是可以共用一个Pattern对象的。
现在我们先来看一个简单的例子,再通过分析它来了解怎样生成一个Pattern对象并且编译一个正则表达式,最后根据这个正则表达式将目标字符串进行分割:
[html] view plain copy print?
import java.util.regex.*;
public class Replacement{
public static void main(String[] args) throws Exception {
// 生成一个Pattern,同时编译一个正则表达式
Pattern p = Pattern.compile("[/]+");
//用Pattern的split()方法把字符串按"/"分割
String[] result = p.split(
"Kevin has seen《LEON》seveal times,because it is a good film."
+"/ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部"
+"好电影。/名词:凯文。");
for (int i=0; i<result.length; i++)
System.out.println(result[i]);
}
}
import java.util.regex.*;
public class Replacement{
public static void main(String[] args) throws Exception {
// 生成一个Pattern,同时编译一个正则表达式
Pattern p = Pattern.compile("[/]+");
//用Pattern的split()方法把字符串按"/"分割
String[] result = p.split(
"Kevin has seen《LEON》seveal times,because it is a good film."
+"/ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部"
+"好电影。/名词:凯文。");
for (int i=0; i<result.length; i++)
System.out.println(result[i]);
}
}
输出结果为:
Kevin has seen《LEON》seveal times,because it is a good film.
凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。
名词:凯文。
很明显,该程序将字符串按"/"进行了分段。
我们以下再使用 split(CharSequence input, int limit)方法来指定分段的段数,程序改动为:
tring[] result = p.split("Kevin has seen《LEON》seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。/名词:凯文。",2);
这里面的参数"2"表明将目标语句分为两段。
输出结果则为: