1.正则表达式简介
正则表达式(Regular expression,简写为Regexes)是一种用来操作和检验字符串数据的强大工具。它相当与一串特殊的字符,用它可以转换成算法,对文本进行匹配等操作。
事实上正则表达式有其自身的一套语法,这种语法对于初学者来说显得有些晦涩难懂。尤其是其构造比较困难,称为很多入门者的障碍。但当掌握后却可以轻易的解决以前不容易解决的很多文本类问题,如验证提取等。
其常用场合有如下三种:
Ø 测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证。
Ø 替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字。
Ø 根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字。
2.正则表达式基础语法
2.1匹配不同类型的字符
字符类 |
匹配的字符 |
\d |
匹配一个数字字符。等价于 [0-9]。 |
\D |
匹配一个非数字字符。等价于 [^0-9]。 |
\w |
匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
\W |
匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
\s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [\f\n\r\t\v]。 |
\S |
匹配任何非空白字符。等价于 [^\f\n\r\t\v]。 |
.(点号) |
任一字符 |
[...] |
括号中的任一字符 |
[^…] |
非括号中的任一字符 |
2.2定位控制字符
^ |
其后的模式必须在字符串的开始处,如果是多行则在任一行的开始C#需要设定Multiline标志 |
$ |
前面的模式必须在一行的末尾,如果是多行,则在任意行的末尾 |
\A |
前面的模式必须在字符串的开始处;多行标志被忽略 |
\z |
前面的模式必须在字符串的末尾处,多行标志被忽略 |
\Z |
前面的模式必须位于字符串的末尾或位于换行符前 |
\b |
匹配一个单词字符的开始,单词字符是[a-zA-Z0-9]中的一位 |
\B |
匹配一个非单词边界的位置, 不在一个单词的开始 |
2.3指定重复字符
{n} |
匹配前面的字符n次 |
{n,} |
匹配前面的字符最少n次 |
匹配前面的字符n至m次 |
|
? |
匹配前面的字符0次或1次 |
+ |
匹配前面的字符至少1次 |
* |
匹配前面的字符至少0次 |
2.4特殊控制类
| |
指定字符替换,即该位置可以是|两边的任一个表达式 |
2.5 特殊字符转义序列
\\ |
匹配”\” |
\. |
匹配“.” |
\* |
匹配“*” |
\( |
匹配“(” |
\) |
匹配”)” |
\? |
匹配“?“ |
\+ |
匹配“+“ |
\| |
匹配“|“ |
\{ |
匹配“{“ |
\} |
匹配“}“ |
\^ |
匹配“^“ |
\$ |
匹配“$“ |
\n |
匹配换行符 |
\r |
匹配回车 |
\t |
匹配Tab键 |
\v |
匹配垂直制表符 |
\f |
匹配换页符 |
\nnn |
匹配一个三位八进制数指定的ASCII字符,如\103匹配C |
\xnn |
匹配一个二位16进制数指定的ASCII字符,例如\x43匹配C |
\unnnn |
匹配一个4位16进制数指定的Unicode字符 |
\cV |
匹配一个控制字符,(如复制Ctrl+C) |
2.6正则表达式分组、替换、反向引用等高级应用
以上只是正则表达式的基础部分,从这里开始才算真正开始正则表达式之旅。
² 分组
分组技术可以匹配在一个组中的所有字符,用()来表示,是下面两个技术的基础所在。“()“又称捕获符号。
1. 捕获:()
例子:ABC1EDF2UU
匹配组表达式:([A-Z]{3})\d --匹配3个连续大写字母和一个数字
匹配结果:1.ABC1,2.EDF2
如果用C#中的group,则为ABC,EDF。因为group搜集的是匹配组的内容。
2.非捕获(?:)
使用了非捕获就说明该()中的内容将不作为捕获的组返回,而和其它表达式共同构成匹配项返回。也就是捕获组将不存在。
例:1AF3EDC
匹配表达式:(?:\d|[A-Z])\w --匹配一个数字或字母加一个任意的字符。
匹配结果:1.1A 2.F3 3.ED
没有组被捕获
2. 通过名称捕获(?<name>)
定义了名称捕获的组可以在反向匹配中运用名称进行反向引用而不需要再使用数字进行反向捕获。注意组名区分大小写!
² 替换
替换,顾名思义,是将匹配的字符替换成其他指定的字符形式。这个功能是在分组的基础上的(当然或许可以单独存在,但是那样匹配的功能显然不够强大)。在这里有一个技巧是使用附加的匹配字符控制匹配内容。
$group |
用group指定的组号进行替换 |
${name} |
替换由<?name>匹配的最后一个子串 |
$$ |
替换字符$ |
$& |
替换整个的匹配 |
$+ |
替换最后捕获的组 |
$ |
替换整个输入的字符串 |
² 反向引用
反向匹配可以引用前面组中的匹配形式。“\匹配组的数字表示(1为基数)“或者”\k<groupname>“
² 高级组
1. 正声明(?=)
规定了括号中的模式必须出现在声明的右侧。模式将不构成匹配的一部分。
2. 负声明(?!)
规定了括号中的模式不能出现在声明的右侧,模式将不构成匹配的一部分。
3. 反向正声明(?<=)
规定了括号中的模式必须出现在声明的左侧,模式将不构成匹配的一部分。
4. 反向负声明(?<!)
规定了括号中的模式必须出现在声明的左侧。模式不构成匹配的一部分。
5. 非回溯(?>)
防止了正则表达式引擎搜索失败时回溯,这称之为贪婪的子表达式。
如输入字符串:He was very trusting.
正则表达式:.*ing将匹配trusting但是如果加入(?>)ing则不能完成匹配。
非回溯组也是非捕获组。他对于提高正则表达式的效率很有效。
如匹配一个www.****.com的网址。使用www\.(.*)\.com显然要比www\.([^.]*)\.com效率要低的多,因为前者必须使用组中的回溯操作,回溯是很艰难的过程,所以当使用非回溯的正则表达式时时可以显著提高正则表达式的效率的。
其实正则表达式是只注重匹配结果的,所以会努力去匹配所存在的字符串。这就是它的贪婪性所在。(这点其实理解的不是太深)。
注意以上这些(1-5)都不能够用于反向引用,因为以上声明将不作为匹配的一部分。
2.7在正则表达式中做决策
高级决策的两种写法:
1=>(?(expression)yes|no)
2=>(?(?=expression)yes|no)
这两种方式中的的expression匹配则后面进行匹配yes,否则匹配no。
需要注意的一点是yes测试和决策测试是在同一个起点里进行的。
如以下字符串:77-77A 69-AA 57-B
匹配表达式为:(\d7)?-(?(1)\d\d[A-Z]|[A-Z][A-Z])
匹配结果为:
1.77-77A 2. –AA
这个正则表达式中用到了引用组,(?(1)**)中的1也可以换为\1,这样不影响匹配。这个匹配中如果将决策后面的\d\d去掉则会出现不同的结果,这时只会有一个-AA是匹配的。因为决策点和yes表达式是从同一个起点开始匹配所以即使决策点匹配了,但是后面的yes表达式仍然不匹配。就只匹配no部分的表达式。最终结果也必然改变,理解这一点很重要。
2.8 正则表达式的选项
快到结尾了,再说下正则表达式的选项。选项其实就是将正则表达式的设置改到组中来。如(?i:[a-z])将忽略大小写进行匹配。实际上如果学过Javascript中的正则表达式,可以看出这个i在javascript中表示的还是这个意思。
N |
规定只有显示命名的组标号的组才能有效的捕获 |
I |
此选项匹配不区分大小写的匹配 |
X |
此选项规定,非转义的空字符被排除在模式之外,并启用了一个前缀#的注释 |
M |
指定多行模式,修改了^和$的定义 |
S |
指定单行模式 |
2.9正则表达式的规则
1.正则表达式会对输入字符传进行最快的匹配,它一次搜索一个字符,知道实现第一次匹配。
2.发现一个匹配的开始后,正则表达式引擎将继续匹配,直到遇到一个不被模式接收的字符。
3.Regex引擎非常贪婪—只要模式匹配它将匹配尽可能多的字符。
4.Regex渴望实现匹配,所以将在需要时回溯以实现匹配。
5.Regex引擎总是先选择第一个选项。在|式表达式中。
以上的几点很重要。到这正则表达式的几乎所有规则也就讲完了。
最后附一个懒惰匹配常用修饰和其他的限定
*? |
尽可能少地使用重复的第一个匹配 |
+? |
尽可能少地使用重复但至少使用一次 |
?? |
使用零次重复(如有可能)或一次重复 |
{n}? |
等同于{n} |
{n,}? |
尽可能少地使用重复但至少使用n次 |
介于n和m之间,尽可能少地使用重复 |
应用:
匹配中文字符的正则表达式:
匹配双字节字符(包括汉字在内):
应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
匹配空行的正则表达式:
匹配HTML标记的正则表达式:
匹配首尾空格的正则表达式:
应用:j avascript中没有像v bscript那样的trim函数,我们就可以利用这个表达式来实现,如下:
{
return this . replace ( / (^\s*)|(\s*$) /g , "" ) ;
}
利用正则表达式分解和转换IP地址
下面是利用正则表达式匹配IP地址,并将IP地址转换成对应数值的Javascript程序:
{
re = / (\d+)\.(\d+)\.(\d+)\.(\d+) /g //匹配IP地址的正则表达式
if ( re . test ( ip ))
{
return RegExp .$ 1 * Math . pow ( 255 , 3 ) )+ RegExp .$ 2 * Math . pow ( 255 , 2 ) )+ RegExp .$ 3 * 255 + RegExp .$ 4 * 1
}
else
{
throw new Error ( " Not a valid IP address! " )
}
}
不过上面的程序如果不用正则表达式,而直接用split函数来分解可能更简单,程序如下:
ip = ip . split ( " . " )
alert ( " IP值是: " + ( ip [ 0 ] * 255 * 255 * 255 + ip [ 1 ] * 255 * 255 + ip [ 2 ] * 255 + ip [ 3 ] * 1 ))
匹配Email地址的正则表达式:
匹配网址URL的正则表达式:
利用正则表达式去除字串中重复的字符的算法程序:[*注:此程序不正确]
var s1 = s . replace ( / (.).*\1 /g , " $1 " )
var re = new RegExp ( " [ " + s1 + " ] " , " g " )
var s2 = s . replace ( re , "" )
alert ( s1 + s2 ) //结果为:abcefgi
*注
===============================
如果var s = “abacabefggeeii”
结果就不对了,结果为:abeicfgg
正则表达式的能力有限
===============================
我原来在CSDN上发贴寻求一个表达式来实现去除重复字符的方法,最终没有找到,这是我能想到的最简单的实现方法。思路是使用后向引用取出包括重复的字符,再以重复的字符建立第二个表达式,取到不重复的字符,两者串连。这个方法对于字符顺序有要求的字符串可能不适用。
得用正则表达式从URL地址中提取文件名的javascript程序,如下结果为page1
s = s . replace ( / (.* \/ ){ 0,}([^\.]+).* /i g , " $2 " )
alert ( s )
利用正则表达式限制网页表单里的文本框输入内容:
用正则表达式限制只能输入中文:
用正则表达式限制只能输入全角字符:
用正则表达式限制只能输入数字:
用正则表达式限制只能输入数字和英文:
匹配非负整数(正整数 + 0)
匹配正整数
匹配非正整数(负整数 + 0)
匹配负整数
匹配整数
匹配非负浮点数(正浮点数 + 0)
匹配正浮点数
匹配非正浮点数(负浮点数 + 0)
匹配负浮点数
匹配浮点数
匹配由26个英文字母组成的字符串
匹配由26个英文字母的大写组成的字符串
匹配由26个英文字母的小写组成的字符串
匹配由数字和26个英文字母组成的字符串
匹配由数字、26个英文字母或者下划线组成的字符串
匹配email地址
匹配url
匹配html tag
Visual Basic & C# Regular Expression
1.确认有效电子邮件格式
下面的示例使用静态 Regex.IsMatch 方法验证一个字符串是否为有效电子邮件格式。如果字符串包含一个有效的电子邮件地址,则 IsValidEmail 方法返回 true,否则返回 false,但不采取其他任何操作。您可以使用 IsValidEmail,在应用程序将地址存储在数据库中或显示在 ASP.NET 页中之前,筛选出包含无效字符的电子邮件地址。
[Visual Basic]
' Return true if strIn is in valid e-mail format.
Return Regex.IsMatch(strIn,("^([\w-\.]+)@((\[[0-9]{ 1,3 }\.[0-9]{ 1,3 }\.)|(([\w-]+\.)+))([a-zA-Z]{ 2,4 }|[0-9]{ 1,3 })(\]?)$")
End Function
[C#]
{
// Return true if strIn is in valid e-mail format.
return Regex.IsMatch(strIn,@"^([\w-\.]+)@((\[[0-9]{ 1,3 })(\]?)$");
}
2.清理输入字符串
下面的代码示例使用静态 Regex.Replace 方法从字符串中抽出无效字符。您可以使用这里定义的 CleanInput 方法,清除掉在接受用户输入的窗体的文本字段中输入的可能有害的字符。CleanInput 在清除掉除 @、-(连字符)和 .(句点)以外的所有非字母数字字符后返回一个字符串。
[Visual Basic]
' Replace invalid characters with empty strings.
Return Regex.Replace(strIn,"[^\w\.@-]","")
End Function
[C#]
{
// Replace invalid characters with empty strings.
return Regex.Replace(strIn,@"[^\w\.@-]","");
}
3.更改日期格式
以下代码示例使用 Regex.Replace 方法来用 dd-mm-yy 的日期形式代替 mm/dd/yy 的日期形式。
[Visual Basic]
Return Regex.Replace(input,_
"\b(?<month>\d{ 1,2 })/(?<day>\d{ 1,2 })/(?<year>\d{ 2,4 })\b",_
"${ day }-${ month }-${ year }")
End Function
[C#]
{
return Regex.Replace(input,"\\b(?<month>\\d{ 1,2 })/(?<day>\\d{ 1,2 })/(?<year>\\d{ 2,4 })\\b","${ day }-${ month }-${ year }");
}
Regex 替换模式
本示例说明如何在 Regex.Replace 的替换模式中使用命名的反向引用。其中,替换表达式 ${ day } 插入由 (?…) 组捕获的子字符串。
有几种静态函数使您可以在使用正则表达式操作时无需创建显式正则表达式对象,而 Regex.Replace 函数正是其中之一。如果您不想保留编译的正则表达式,这将给您带来方便
4.提取 URL 信息
以下代码示例使用 Match.Result 来从 URL 提取协议和端口号。例如,“http://www.penner.cn:8080……将返回“http:8080”。
[Visual Basic]
Dim r As New Regex("^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",_
RegexOptions.Compiled)
Return r.Match(url).Result("${ proto }${ port }")
End Function
[C#]
{
Regex r = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",
RegexOptions.Compiled);
return r.Match(url).Result("${ proto }${ port }");
}
只有字母和数字,不小于6位,且数字字母都包含的密码的正则表达式
在C#中,可以用这个来表示:
一个将需要将路径字符串拆分为根目录和子目录两部分的算法程序,考虑路径格式有:C:\aa\bb\cc ,\\aa\bb\cc , ftp://aa.bb/cc 上述路径将分别被拆分为:C:\和aa\bb\cc ,\\aa 和 \bb\cc , ftp:// 和 aa.bb/cc 用javascript实现如下:
var regPathParse = / ^([^\\^ \/ ]+[\\ \/ ]+|\\\\[^\\]+)(.*)$ /
if ( regPathParse . test ( strFolder ))
{
strRoot = RegExp .$ 1
strSub = RegExp .$ 2
}