元字符
描述
.点
匹配任何单个字符。例如正则表达式r.t匹配这些字符串:rat、rut、r t,但是不匹配root。
$
匹配行结束符。例如正则表达式weasel$ 能够匹配字符串"He's a weasel"的末尾 ,但是不能匹配字符串"They are a bunch of weasels."
^
匹配一行的开始。例如正则表达式^When in能够匹配字符串"When in the course of human events"的开始,但是不能匹配"What and When in the"
*
匹配0或多个正好在它之前的那个字符。例如正则表达式.*意味着能够匹配任意数量的任何字符。
\
这是引用符,用来将这里列出的这些元字符当作普通的字符来进行匹配。例如正则表达式\$被用来匹配美元符号,而不是行尾,类似的,正则表达式\.用来匹配点字符,而不是任何字符的通配符。
[ ]
[c1-c2]
[^c1-c2]
匹配括号中的任何一个字符。例如正则表达式r[aou]t匹配rat、rot和rut,但是不匹配ret。可以在括号中使用连字符-来指定字符的区间,例如正则表达式[0-9]可以匹配任何数字字符;还可以制定多个区间,例如正则表达式[A-Za-z]可以匹配任何大小写字母。另一个重要的用法是“排除”,要想匹配除了指定区间之外的字符——也就是所谓的补集——在左边的括号和第一个字符之间使用^字符,例如正则表达式[^269A-Z] 将匹配除了2、6、9和所有大写字母之外的任何字符。
\< \>
匹配词(word)的开始(\<)和结束(\>)。例如正则表达式\<the\>能够匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:这个元字符不是所有的软件都支持的。
\( \)
将 \( 和 \) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。
|
将两个匹配条件进行逻辑“或”(Or)运算。例如正则表达式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:这个元字符不是所有的软件都支持的。
+
匹配1或多个正好在它之前的那个字符。例如正则表达式9+匹配9、99、999等。注意:这个元字符不是所有的软件都支持的。
?
匹配0或1个正好在它之前的那个字符。注意:这个元字符不是所有的软件都支持的。
\{i\}
\{i,j\}
匹配指定数目的字符,这些字符是在它之前的表达式定义的。例如正则表达式A[0-9]\{3\} 能够匹配字符"A"后面跟着正好3个数字字符的串,例如A123、A348等,但是不匹配A1234。而正则表达式[0-9]\{4,6\} 匹配连续的任意4个、5个或者6个数字字符。注意:这个元字符不是所有的软件都支持的。
/*******************匹配常见的格式*********************/ //var pattern=/^\w{5,10}$/; //最少5位的下划线、字母、数字,\w+相当于\w{1,} \w*相当于\w{0,} \w?相当于\w{0,1} \w{5,10}5到10位 //var pattern1=/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;//15位的身份证 //var pattern2=/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$/;//18位的身份证 //var pattern=/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;//匹配E-MALI地址 //var pattern=/^http:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;//匹配网址 //var pattern=/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;//匹配网址 //var pattern=/^[\u4e00-\u9fa5]$/;//匹配中文字符(单个汉字) //var pattern=/^[1-9]\d{5}(?!\d)$/;//匹配邮政编码 //var pattern=/^[1-2][0-9][0-9][0-9]-[0-1]{0,1}[0-9]-[0-3]{0,1}[0-9]$/;//匹配日期 如:1900-01-01 //var pattern=/^[^\x00-\xff]$/;//匹配双字节字符(包括汉字在内的单个字符) //var pattern=/^<(.*)>.*<\/\1>|<(.*) \/>$/;//匹配HTML标记 //var pattern=/<(\S*?)[^>]*>.*?<\/\1>|<.*? \/>/;//匹配HTML标记 //var pattern=/^\n[\s| ]*\r$/;//可以用来删除空白行 //var pattern=/^(\s*)|(\s*)$///可以用来删除行首尾的空白字符(包括空格、制表符、换页符等等) //var pattern=/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/;//字母开头,限制5-16字节,允许字母数字下划线 //var pattern=/^\d{3}-\d{8}|\d{4}-\d{7,8}$/;//匹配国内电话 如:0739-8888888(8) 或 020-88888888 //var pattern=/^[1-9][0-9]{4,}$/;//匹配QQ号码 腾讯QQ号从10000开始 //var pattern=/^\d+\.\d+\.\d+\.\d+$/;//匹配IP地址 /*******************匹配特定数字*********************/ //var pattern=/^(\w)\1{4,}*$/;//匹配整数 //var pattern=/-?[1-9]\d*$/;//匹配整数 //var pattern=/^[1-9]\d*$/;//匹配正整数 //var pattern=/^-[1-9]\d*$/;//匹配负整数 //var pattern=/^[1-9]\d*|0$/;//匹配非负整数 //var pattern=/^-[1-9]\d*|0$/;//匹配非正整数 //var pattern=/^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$/;//匹配正浮点数 //var pattern=/^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$/;//匹配负浮点数 //var pattern=/^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$/;//匹配浮点数 //var pattern=/^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$/;//匹配非负浮点数 //var pattern=/^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$/;//匹配非正浮点数 /********************匹配特定字符串*****************/ //var pattern=/^[A-Za-z]+$/;//匹配由26个英文字母组成的字符串 //var pattern=/^[A-Z]+$/;//匹配由26个英文字母的大写组成的字符串 //var pattern=/^[a-z]+$/;//匹配由26个英文字母的小写组成的字符串 //var pattern=/^[A-Za-z0-9]+$/;//匹配由数字和26个英文字母组成的字符串 //var pattern=/^\w+$/;//匹配由数字、26个英文字母或者下划线组成的字符串 <script> if(!pattern.test(document.getElementById("content").value)){ alert("请输入正确的格式!"); return false; } } </script> <% ‘限制只能输入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,‘‘)" onbeforepaste="clipboardData.setData(‘text‘,clipboardData.getData(‘text‘).replace(/[^\u4E00-\u9FA5]/g,‘‘))" ‘限制只能输入全角字符:onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,‘‘)" onbeforepaste="clipboardData.setData(‘text‘,clipboardData.getData(‘text‘).replace(/[^\uFF00-\uFFFF]/g,‘‘))" ‘限制只能输入数字:onkeyup="value=value.replace(/[^\d]/g,‘‘) "onbeforepaste="clipboardData.setData(‘text‘,clipboardData.getData(‘text‘).replace(/[^\d]/g,‘‘))" ‘限制只能输入数字和英文:onkeyup="value=value.replace(/[\W]/g,‘‘) "onbeforepaste="clipboardData.setData(‘text‘,clipboardData.getData(‘text‘).replace(/[^\d]/g,‘‘))" %>
匹配模式+环视(顺序环视、逆序环视)+贪婪与非贪婪 RegexOptions.Multiline “^”匹配结果分析 在不开启多行模式时,“^”只匹配字符串的开始位置,也就是位置0。 在开启了多行模式后,“^”匹配字符串开始位置和每个“\n”之后的行起始位置。 “$”匹配结果分析 在不开启多行模式时,如果字符结尾是“\n”,那么“$”会匹配结尾“\n”之前和结束两个位置。 在开启多行模式后,“$”匹配每行“\n”之前的位置和字符串结束位置。 需要注意的是,在.NET中,无论是否开启多行模式,“^”和“$”匹配的都只是一个位置,是零宽度的。其它语言中“^”和“$”的意义可能会有所不同。 只有在正则表达式中涉及到多行的“^”和“$”的匹配时,才使用Multiline模式。 RegexOptions.Compiled Compiled改变的是.NET中正则表达式的编译方式。启用了Compiled模式,会延长启动时间,占用更多的内存,会提高匹配速度。当然,对最终性能的影响,需要根据具体问题综合考虑的。这一模式也是被“滥”用最多的模式之一。 程序运行过程中,第一次遇到正则表达式,需要加载正则引擎,对正则表达式进行必要的语法检查,并做适当的优化,最后把它转换为适合正则引擎应用的形式。这种“解析”过程,对于复杂的正则表达式,频繁调用或是匹配较大的数据源时,对效率的影响较大。 这时可以在构建正则表达式时开启Compiled模式。这样做会将正则表达式直接编译为MSIL代码,在正则匹配过程中,可以由JIT优化为更快的本地机器代码,获得更高的匹配速度。但这种方式会降低正则的解析速度,占用更多的内存,而且它占用的内存在程序运行过程中会一直占用,无法释放。 什么场景下使用Compiled模式,需要根据实际情况具体问题具体分析,一般来说,以下场景不适合使用Compiled模式: 1.对匹配效率没有要求的场景; 2.非常简单的正则表达式; 3.极少调用的方法中声明的正则表达式; 4.循环体中声明的正则表达式(除了动态生成的正则表达式,否则不要在循环体内声明正则表达式); 5.静态方法中声明的正则表达式(静态方法每次调用都需要重新编辑正则表达式,使用Compiled模式只会降低效率)。 RegexOptions.RightToLeft RightToLeft改变的是正则表达式匹配的顺序,从右到左进行匹配 一个由字母组成的字符串,最长14位,要求每隔2位加一个逗号,最左边不加,求一个好的算法 例:“abcdefg” 返回“a,bc,de,fg” 代码实现: string test = "abcdefg"; string result = Regex.Replace(test, @"(?<!^)[a-zA-Z]{2}", ",$0", RegexOptions.RightToLeft); RegexOptions.ExplicitCapture 这一模式改变的是普通捕获组的匹配行为。将普通捕获组解释为非捕获组,只有显式命名的命名捕获组才当作捕获组使用。 捕获组的作用是将括号()内子表达式匹配到的内容保存到内存中一个组里,供以后引用,在.NET中捕获组有两种形式 (Expression) 普通捕获组 (?<name>Expression) 命名捕获组 其它形式的(?...)都不是捕获组。 但是(Expression)这种捕获组语法规则也带来一个副作用,在一些不得不使用()的场合,会默认为使用了捕获组,将匹配到的内容保存到内存中,而有些情况下这些内容并不需要关心的,浪费了系统资源,降低了匹配效率,所以才有了非捕获组(?:Expression)的出现,来抵消这一副作用。而非捕获组带来的另一个副作用的就是可读性的降低。 string test = "<li title=\"截至2009-07-28 20:45:49,用户的总技术分为:5988;截至2009-07-26日,用户的总技术分排名为:4133\">(...)</li>"; Regex reg = new Regex(@"([01][0-9]|2[0-3])(:[0-5][0-9]){2}", RegexOptions.ExplicitCapture); MatchCollection mc = reg.Matches(test); string s = ""; foreach (Match m in mc) { s += m.Value + "\n"; s += m.Groups[1].Value + "\n"; s += m.Groups[2].Value + "\n"; } Console.Write(s); 未开启RegexOptions.ExplicitCapture /* 20:45:49 20 :49 */ 开启的结果是 /* 20:45:49 */ (?imnsx-imnsx:)形式 string[] test = new string[] { "Abc", "AbcdefGHIjklmn", "abcdefghijklmn" }; Regex reg = new Regex(@"^[A-Z](?i:[A-Z]{9,19})$"); string str = ""; foreach (string s in test) { str += "源字符串:" + s.PadRight(15, ' ') + " 匹配结果: " + reg.IsMatch(s) + "\n"; } Console.WriteLine(str); /*--------输出-------- 源字符串: Abc 匹配结果: False 源字符串: AbcdefGHIjklmn 匹配结果: True 源字符串: abcdefghijklmn 匹配结果: False */ 语法:(?-i:Expression) 这种语法规则表达为括号内的子表达式关闭忽略大小写模式。通常与全局匹配模式配合使用,表示全局为忽略大小写的,局部为严格区分大小写。 string test = "<DIV id=\"Test\" class=\"create\">first</div> and <DIV id=\"TEST\" class=\"delete\">second</div>"; Regex reg = new Regex(@"<div id=""(?-i:TEST)""[^>]*>[\w\s]+</div>", RegexOptions.IgnoreCase); string str = ""; MatchCollection mc = reg.Matches(test); foreach (Match m in mc) { str += m.Value + "\n"; } Console.WriteLine(str); /*--------输出-------- <DIV id="TEST" class="delete">second</div> */ 环视基础 表达式 说明 (?<=Expression) 逆序肯定环视,表示所在位置左侧能够匹配Expression (?<!Expression) 逆序否定环视,表示所在位置左侧不能匹配Expression (?=Expression) 顺序肯定环视,表示所在位置右侧能够匹配Expression (?!Expression) 顺序否定环视,表示所在位置右侧不能匹配Expression string str = "aa<p>one</p>bb<div>two</div>cc"; foreach (Match item in Regex.Matches(str, @"<(?!/?p\b)[^>]+>")) { Console.WriteLine(item.Value); } /* <div> </div> */ string str = "<div>a test</div><div>1</div>"; foreach (Match item in Regex.Matches(str, @"(?<=<div>)[^<]+(?=</div>)")) { Console.WriteLine(item.Value); } /* a test 1 */ double[] data = new double[] { 0, 12, 123, 1234, 12345, 123456, 1234567, 123456789, 1234567890, 12.345, 123.456, 1234.56, 12345.6789, 123456.789, 1234567.89, 12345678.9 }; string s = ""; foreach (double d in data) { s += "源字符串:" + d.ToString().PadRight(15) + "格式化:" + Regex.Replace(d.ToString(), @"(?<=\d)(?<!\.\d*)(?=(?:\d{3})+(?:\.\d+|$))", ",") + "\n"; } Console.Write(s); 结果: 源字符串:0 格式化:0 源字符串:12 格式化:12 源字符串:123 格式化:123 源字符串:1234 格式化:1,234 源字符串:12345 格式化:12,345 源字符串:123456 格式化:123,456 源字符串:1234567 格式化:1,234,567 源字符串:123456789 格式化:123,456,789 源字符串:1234567890 格式化:1,234,567,890 源字符串:12.345 格式化:12.345 源字符串:123.456 格式化:123.456 源字符串:1234.56 格式化:1,234.56 源字符串:12345.6789 格式化:12,345.6789 源字符串:123456.789 格式化:123,456.789 源字符串:1234567.89 格式化:1,234,567.89 源字符串:12345678.9 格式化:12,345,678.9 实现分析: 首先根据需求可以确定是把一些特定的位置替换为“,”,接下来就是分析并找到这些位置的规律,并抽象出来以正则表达式来表示。 1、这个位置的左侧必须为数字 2、这个位置右侧到出现“.”或结尾为止,必须是数字,且数字的个数必须为3的倍数 3、这个位置左侧相隔任意个数字不能出现“.” 由以上三条,就可以完全确定这些位置,只要实现以上三条,组合一下正则表达式就可以了。 根据分析,最终匹配的结果是一个位置,所以所有子表达式都要求是零宽度。 1、是对当前所在位置左侧附加的条件,所以要用到逆序环视,因为要求必须出现,所以是肯定的,符合这一条件的子表达式即为“(?<=\d)” 2、是对当前所在位置右侧附加的条件,所以要用到顺序环视,也是要求出现,所以是肯定的,是数字,且个数为3的倍数,即“(?=(?:\d{3})*)”,到出现“.”或结尾为止,即“(?=(?:\d{3})*(?:\.|$))” 3、是对当前所在位置左侧附加的条件,所以要用到逆序环视,因为要求不能出现,所以是否定的,即“(?<!\.\d*)” 因为零宽度的子表达式是非互斥的,最后匹配的都是同一个位置,所以先后顺序是不影响最后的匹配结果的,可以任意组合,只是习惯上把逆序环视写在左侧,顺序环视写在右侧。 贪婪与非贪婪模式匹配 string str = "aa<div>test1</div>bb<div>test2</div>cc"; foreach (Match item in Regex.Matches(str, @"<div>.*</div>")) { Console.WriteLine(item.Value); } /*贪婪模式,很好理解,尽量多匹配 <div>test1</div>bb<div>test2</div> */ 如果正则表达式是<div>.*?</div> /*非贪婪模式,也叫懒惰模式,就是懒的意思,匹配到了就不会再向后匹配 <div>test1</div> <div>test2</div> */ 贪婪非贪婪的比较以及优化 string str =@"The phrase ""regular expression"" is called ""Regex"" for short."; foreach (Match item in Regex.Matches(str, @""".*""")) { Console.WriteLine(item.Value); } 一、使用”.*”这种匹配的结果不符合:"regular expression" is called "Regex" 二、使用”.*?”的结果: "regular expression" "Regex" OK,不过进行了四次回溯 三、使用这种[^"]*匹配OK,没有回溯 四、对三的改进,固化分组 (?>[^"]*),匹配效率最好 再看一例,获取img标签的src内容: string str =@"<img class=""test"" src=""/img/logo.gif"" title=""测试"" />"; foreach (Match item in Regex.Matches(str, @"<img\b.*?src=""(.*?)"".*?")) { Console.WriteLine(item.Groups[1].Value); } 使用的是非贪婪模式,我们通过排除型字符组转换为贪婪模式,提高匹配效率 @"<img\b.*?src=""([^""]*)""[^>]*" img与src之间的非贪婪通过顺序环视来转化 @"<img\b(?:(?!src=).)*src=""([^""]*)""[^>]*" “(?!src=).”表示这样一个字符,从它开始,右侧不能是字符序列“src=”,而“(?:(?!src=).)*”就表示符合上面规则的字符,有0个或无限多个。这样就达到排除字符序列的目的,实现的效果同排除型字符组一样,只不过排除型字符组排除的是一个或多个字符,而这种环视结构排除的是一个或多个有序的字符序列。 但是以顺序环视的方式排除字符序列,由于在匹配每一个字符时,都要进行较多的判断,所以相对于非贪婪模式,是提升效率还是降低效率,要根据实际情况进行分析。对于简单的正则表达式,或是简单的源字符串,一般来说是非贪婪模式效率高些,而对于数量较大源字符串,或是复杂的正则表达式,一般来说是贪婪模式效率高些。 PS:一般都是贪婪模式+固化分组,当然也需要看具体情况。 一些正则的实践篇 清除掉iframe+javascript+css的恶意脚本 http://rczjp.cn/HTML/101210/20105010115029.html 正则截取URL网址 http://rczjp.cn/HTML/101218/20102718032702.html 常见的正则 http://rczjp.cn/HTML/081119/20082119022155.html 此文章来自原作者:http://blog.csdn.net/lxcnn/ 具体详情去过客的blog参看。 下面是作者写的NFA引擎匹配原理,讲解的很详细,值得参看: http://blog.csdn.net/lxcnn/archive/2009/06/28/4304651.aspx