正则表达式(I)
正则表达式是由英文词语regular expression翻译过来的,就是符合某种规则的表达式。正则表达式在软件开发中应用非常广泛,例如,找出网页中的超链接,找出网页中的email地址,找出网页中的手机号码,判断输入的内容是否全部是数字,是否满足某种日期格式等等。
可以将正则表达式理解为一种对文字进行模糊匹配的语言,它用一些特殊的符号(称为元字符)来代表具有某种特征的一组字符以及该组字符重复出现的次数。例如,对于正则表达式“\d{5}(-\d{4})?”,\d就是一个元字符,它表示一个数字字,{5}表示紧靠它前面的元素项连续重复5次,\d和{5}的组合\d{5}就表示匹配任意连续的5个数字字符;-\d{4}匹配的是一个连字号(-)后加上4个任意的数字,(-\d{4})?表示连字号(-)和后面的4个数字可有可无。对于整个正则表达式“\d{5}(-\d{4})?”,表示要么是5个连续的数字字符,要么是5个连续的数字后加上一个连字号(-)、再加上4个连续的数字组成的10个字符。正则表达式中的圆括号除了能将多个元素组合成一个可统一操作的组合项外,它所括起来的表达式部分还成为了一个子匹配(也叫子表达式),也就是说,我们可以用圆括号在一个长的正则表达式中划分出子表达式。这样,除了可以得到整个正则表达式的匹配结果外,还可以单独得到每个子表达式部分所匹配的结果。
要灵活运用正则表达式,必须了解其中各种元字符的功能。元字符从功能上大致分为:限定符、选择匹配符、分组组合和反向引用符、特殊字符、字符匹配符、定位符。
限定符用于指定其前面的字符或组合项连续出现多少次,下面是各种限定符及其含义:
l {n} 规定前面的元素或组合项的连续出现n 次
l {n,} 规定前面的元素或组合项至少连续出现n 次
l {n,m } 规定前面的元素或组合项至少连续出现n 次,至多连续出现m 次
l + 规定前面的元素或组合项必须出现一次或连续多次,等效于 {1,}
l * 规定前面的元素或组合项可以出现零次或连续多次,等效于 {0,}
l ? 规定前面的元素或组合项出现零次或一次,等效于 {0,1}
默认情况下,正则表达式使用最长(也叫贪婪)匹配原则。当字符“?”紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式变成使用最短(也叫非贪婪)匹配原则。例如,在字符串“fooood”中,“fo+?”只匹配“fo”部分,而“fo+”匹配“foooo”部分。
选择匹配符就是“|”字符,用于选择匹配两个选项之中的任意一个,选择匹配符的优先级低于任意字符,即“|”字符的两个选项是它两边尽可能最大的表达式。例如,“chapter|section 1”匹配的是“chapter”或“section 1”,而不是“chapter 1”或“section 1”。
分组组合符就是将正则表达式中的某一部分内容组合起来的符号,反向引用符则是用于匹配前面的分组组合所捕获到的内容。
l (pattern) 将圆括号中的pattern部分组合成一个可统一操作的组合项和子匹配,每个捕获的子匹配项按照它们在正则表达式模式中从左到右出现的顺序存储在缓冲区中。缓冲区从1开始编号,最多可存储99个子匹配捕获的内容。存储在缓冲区中的子匹配捕获的内容,可以在编程语言中被检索,也可以在正则表达式中被反向引用。
l \num 匹配编号为num的缓冲区所保存的内容,此处的 num 是一个标识特定缓冲区的一位或两位十进制正整数,这种方式称为子匹配的反向引用。例如,要匹配连续的5个相同的数字字符,如55555、11111等,需要使用(\d)\1{4}作为正则表达式文本,\1表示与前面的(\d)所捕获的内容一样,\1{4}则表示前面的(\d) 所捕获的内容还连续出现4次。
字符匹配符用于指定该符号部分可以匹配多个字符中的任意一个。
l […] 匹配方括号中包含的字符集中的任意一个字符,例如,“[abc]”可以与“a”、“b”、“c”三个字符中的任何一个相匹配。
l [^…] 匹配方括号中未包含的任何字符,例如,“[^abc]”可以匹配“a”、“b”、“c”3个字符之外的任何字符。
l [a-z] 匹配指定范围内的任何字符,例如,“[1-9]”匹配1~9之间的任何数字字符。
l [^a-z] 匹配不在指定的范围内的任何字符。
l \d 匹配任意一个数字字符,等效于 [0-9]。
l \D 匹配任意一个非数字字符,等效于 [^0-9],为\d的逆运算。
l \s 匹配任何空白字符,包括空格、制表符、换页符等,等效于[ \f\n\r\t\v]。
l \S 匹配任何非空白字符,为\s的逆运算,等效于 [^ \f\n\r\t\v]。
l \w 匹配任何英文字母和数字类字符以及下划线。等效于[A-Za-z0-9_]。
l \W 匹配任何非英文字母和数字类字符,但不包括下划线。为\w的逆运算,等效于[^A-Za-z0-9_]。
l . 匹配除“\n”之外的任何单个字符,例如,“(.)\1”匹配除“\n”之外的两个连续的相同字符。若要匹配包括“\n”在内的任意字符,可以使用“[\s\S]”、“[\d\D]”或“[\w\W]”等模式。若要匹配“.”字符本身,需要使用“\.”。
正则表达式中使用多种方式来表示非打印字符和原义字符,这些方式都是以反斜杠字符(\)后紧跟其他转义字符序列来表示的,其中的一些方式也可以表示普通字符。
l \xn 匹配ASCII码值等于n的字符,此处的 n 必须是两位的十六进制数。例如,“\x41”匹配字符“A”,显然用这种方式可以表示所有非打印字符。注意:“\x041”的意义是“\x04”所表示的字符后跟字符“1”。
l \un 匹配Unicode编码等于n的字符,此处的n 必须是一个四位的十六进制数。例如,\u00A9 匹配版权符号(©),[\u4e00-\u9fa5]则匹配任意一个汉字字符。
定位符用于规定匹配模式在目标字符串中的出现位置。
l ^ 匹配目标字符串的开始位置,也就是规定匹配必须发生在目标字符串的开头处,^必须出现在正则表达式模式文本的最前面才具有定位符作用。
l $ 匹配目标字符串的结尾位置,也就是规定匹配必须发生在目标字符串的结尾处,$必须出现在正则表达式模式文本的最后面才具有定位符作用。
l \b 匹配一个字边界,它包含字与空格间的位置,以及目标字符串的开始和结束位置等。\B 匹配非字边界。
在正则表达式中用到的一些元字符不再表示它原来的字面意义,如果要匹配这些具有特殊意义的元字符的字面意义,必须使用反斜扛(\)将它们转义为原义字符,即将反斜杠字符(\)放在它们前面。需要进行转义的字符有“$”、“(”、“)”、“*”、“+”、“.”、“[”、“]”、“?”、“\”、“/”、“^”、“{”、“}”、“|”。
下面列举出了一些具有典型意义和用途的正则表达式模式文本:
(1)匹配空行:“^\s*$”
(2)匹配HTML标记:“<(\S+)(\s[^>]*)?>[\s\S]*<\/\1\s*>”。
(3)匹配email地址:“[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+”
(4)匹配两个相同的相邻单词:“\b([a-z]+) \1\b”
(5)匹配IP地址:“^\d{1,2}|1\d\d|2[0-4]\d|25[0-5](\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$”
正则表达式(II)
JavaScript中提供了一个名为RegExp的对象来完成有关正则表达式的操作和功能,每一条正则表达式模式对应一个RegExp对象实例。在JavaScript中,有两种方式可以创建RegExp对象的实例:
(1)使用RegExp对象的显示构造函数,语法为:new RegExp("pattern"[,"flags"])
(2)使用RegExp对象的隐式构造函数,采用纯粹的文本格式:/pattern/[flags]
pattern部分为要使用的正则表达式模式文本,是必须的。在第一种方式中,pattern部分以JavaScript字符串的形式存在,需要使用双引号或单引号引起来;在第二种方式中,pattern部分嵌套在两个“/”字符之间,不能使用引号引起来。flags部分设置正则表达式模式的标志信息,是可选的,可以是以下标志字符的组合:
l g 用作全局标志。如果设置了g这个标志,使用这个正则表达式模式对某个文本执行搜索和替换操作时,将对文本中所有匹配的部分起作用。
l i 用作忽略大小写标志。如果设置了i这个标志,进行匹配比较时,将忽略大小写。
l m 用作多行标志。如果没有设置m这个标志,那么元字符“^”只与整个被搜索字符串的开始位置相匹配,而元字符“$”只与整个被搜索字符串的结束位置相匹配。如果设置了m这个标志,那么“^”还可以与被搜索字符串中的“\n”或“\r”之后的位置(即下一行的行首)相匹配,而“$” 还可以与被搜索字符串中的“\n”或“\r”之前的位置(即一行的行尾)相匹配。
下面是在javascript程序中应用正则表达式的一些典型案例:
1.将一个字符串中的所有的两位数字的十位和个位交换:
<script language="javascript">
var strSrc = "a12b34c56";
var re = /\D(\d)(\d)\D/gi;
var strDest = strSrc.replace(re,"$2$1");
alert(strSrc + " has been converted into " + strDest);
</script>
2.使用正则表达式验证身份证和提取其中的年月日:
说明:身份证要么是15位,要么是18位,前面的每位都为数字,最后一位可以为字母,从7位到第14位为出生年月。
<script language="javascript">
function verify(idcard){
var datePattern = new RegExp(
"^\\d{6}(19\\d{2}|20\\d{2})(0[1-9]|1[0-2])(0[1-9]|[1-2]\\d|3[0-1])(\\d{3})?[\\da-zA-Z]$");
if(datePattern.test(idcard)){
alert(idcard + "为有效身份证,出生年月为"
+ RegExp.$1 + "-" + RegExp.$2 + "-" + RegExp.$3);
}else{
alert(idcard + "为无效身份证");
}
}
</script>
请输入身份证:<input type="text" value="422413191803060318" οnblur="verify(this.value)"/>
3.使用正则表达式去掉字符串两端的所有空格:
说明:javascript中的字符串没有去掉两端空格的功能,可以用prototype属性为String类扩 展一个trim方法,以后的String类都可以使用这个trim方法来去掉两端的空格了。
String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g,"");};
alert(1 + " aaa ".strip() + 2);
正则表达式(III)
下面是在java程序中应用正则表达式的一些典型案例:
1. 判断输入的字符串是否是一个email地址:
String content = "z.xx@itcast.cn";
Pattern p = Pattern.compile(
"[a-zA-Z0-9_-][\\.a-zA-Z0-9_-]*@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+");
Matcher m = p.matcher(content);
boolean b = m.matches();
System.out.println(content + (b? "是":"不是" ) + "一个有效的Email地址");
2. 从一篇文档中提取出所有的email地址:
String content = "我的email是z.xx@itcast.cn,你的email是l_h_m@itcast.com.cn";
Pattern p = Pattern.compile(
"[a-zA-Z0-9_-][\\.a-zA-Z0-9_-]*@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+");
Matcher m = p.matcher(content);
while(m.find()){
String email = m.group();
//String email = content.substring(m.start(), m.end());
System.out.println(email);
}
3.通过一个正则表达式即可以将字符串“xx”替换成“xxFileName”,还可以将字符串“xx[n]”替换成“xxFileName[n]”:
String content = "xx[n]"; //改为"xx"试试。
Pattern p = Pattern.compile("\\[.+\\]$|$");
Matcher m = p.matcher(content);
String fileName = m.replaceFirst("FileName$0");
//String fileName = content.replaceFirst("\\[.+\\]$|$", "FileName$0");
System.out.println(fileName);
4.从一封html格式的中文简历中提取出简历人的性别:
说明:性别在简历中通常为如下形式:<td …>性别:</td><td …> 男</td>
另外,简历中的其他地方也可能出现“男”或“女”,例如,“参观了女排的训练”。
String content = "<td …>性别:</td><td …> 男</td>…参观了女排的训练";
Pattern p = Pattern.compile("[^\u4e00-\u9fa5]([男女])[^\u4e00-\u9fa5]");
Matcher m = p.matcher(content);
if(m.find()){
System.out.println("应聘者的性别为:" + m.group(1));
}