zoukankan      html  css  js  c++  java
  • C# 正则表达式及常用正则表达式

    
    

    元字符

    
    

    描述

    
    

    .点

    
    

    匹配任何单个字符。例如正则表达式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}((0d)|(1[0-2]))(([0|1|2]d)|3[0-1])d{3}$/;//15位的身份证 //var pattern2=/^[1-9]d{5}[1-9]d{3}((0d)|(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=/^ [s| ]* $/;//可以用来删除空白行 //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。
    在开启了多行模式后,“^”匹配字符串开始位置和每个“
    ”之后的行起始位置。
     
    “$”匹配结果分析
    在不开启多行模式时,如果字符结尾是“
    ”,那么“$”会匹配结尾“
    ”之前和结束两个位置。
    在开启多行模式后,“$”匹配每行“
    ”之前的位置和字符串结束位置。
     
    需要注意的是,在.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 + "
    ";
    s += m.Groups[1].Value + "
    ";
    s += m.Groups[2].Value + "
    ";
    }
    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) + "
    ";
    }
    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)""[^>]*>[ws]+</div>", RegexOptions.IgnoreCase);
    string str = "";
    MatchCollection mc = reg.Matches(test);
    foreach (Match m in mc)
    {
    str += m.Value + "
    ";
    }
    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)[^>]+>"))
    {
    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+|$))", ",") + "
    ";
    }
    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.*?src=""(.*?)"".*?"))
    {
    Console.WriteLine(item.Groups[1].Value);
    }
    使用的是非贪婪模式,我们通过排除型字符组转换为贪婪模式,提高匹配效率
    @"<img.*?src=""([^""]*)""[^>]*"
    img与src之间的非贪婪通过顺序环视来转化
    @"<img(?:(?!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
  • 相关阅读:
    KKT条件原理
    拉格朗日乘子法
    Java volatile详解
    Java重排序
    Java Socket NIO入门
    Java Socket入门
    TCP三次握手,四次挥手
    Java NIO详解
    cobbler批量安装系统
    nginx详解反向代理,负载均衡,LNMP架构上线动态网站
  • 原文地址:https://www.cnblogs.com/kernel0815/p/3375242.html
Copyright © 2011-2022 走看看