知识大全 正则表达式
Posted 字符
篇首语:爱情不是终点,陪伴才是归宿。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 正则表达式相关的知识,希望对你有一定的参考价值。
C#正则表达式编程(四):正则表达式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
提供了功能强大 灵活而又高效的方法来处理文本 正则表达式的全面模式匹配表示法使您可以快速分析大量文本以找到特定的字符模式 提取 编辑 替换或删除文本子字符串 或将提取的字符串添加到集合以生成报告 对于处理字符串(例如 HTML 处理 日志文件分析和 HTTP 标头分析)的许多应用程序而言 正则表达式是不可缺少的工具 正则表达式是一个非常有用的技术 有人曾称之为能让程序员不至于丢掉饭碗的十大技术之一 可见它的重要性 熟悉DOS或者命令行的朋友或许已经用过类似的功能 比如我们要查找D盘下所有的低于Word 版本的Word文件(因为低于Word 版本的Word文件的文件后缀是 doc 而Word 版本的Word文件的文件后缀是 docx) 我们可以在命令行下执行这个命名 dir D:\\*doc 当然如果想查找D盘下任意级子目录下的所有此类文件 就应该执行dir /s D:\\*doc了 注意正则表达式并不是在中独有的东东 实际上在其它语言中早就实现了 比如(可能很多人没有听说过这个编程语言 十年前大学期间我曾经学过一点皮毛) 其它的编程语言 及等也支持正则表达式 正则表达式差不多像SQL语言一样成为标准了 同样和SQL类似 在不同的厂商那里对SQL标准支持的程度并不完全一样 正则表达式也是如此 大部分内的正则表达式可以跨语言使用 但是在各语言中也会有细微的区别 这一点是需要我们注意的 正则表达式元字符 正则表达式语言由两种基本字符类型组成 原义(正常)文本字符和元字符 元字符使正则表达式具有处理能力 元字符既可以是放在[]中的任意单个字符(如[a]表示匹配单个小写字符a) 也可以是字符序列(如[a d]表示匹配a b c d之间的任意一个字符 而\\w表示任意英文字母和数字及下划线) 下面是一些常见的元字符 元字符 说明 匹配除 \\n 以外的任何字符(注意元字符是小数点) [abcde] 匹配 abcde之中的任意一个字符 [a h] 匹配a到h之间的任意一个字符 [^fgh] 不与fgh之中的任意一个字符匹配 \\w 匹配大小写英文字符及数字 到 之间的任意一个及下划线 相当于[a zA Z _] \\W 不匹配大小写英文字符及数字 到 之间的任意一个 相当于[^a zA Z _] \\s 匹配任何空白字符 相当于[ \\f\\n\\r\\t\\v] \\S 匹配任何非空白字符 相当于[^\\s] \\d 匹配任何 到 之间的单个数字 相当于[ ] \\D 不匹配任何 到 之间的单个数字 相当于 [^ ] [\\u e \\u fa ] 匹配任意单个汉字(这里用的是Unicode编码表示汉字的) 正则表达式限定符 上面的元字符都是针对单个字符匹配的 要想同时匹配多个字符的话 还需要借助限定符 下面是一些常见的限定符(下表中n和m都是表示整数 并且 <n<m) 限定浮 说明 * 匹配 到多个元字符 相当于 ? 匹配 到 个元字符 相当于 n 匹配n个元字符 n 匹配至少n个元字符 n m 匹配n到m个元字符 + 匹配至少 个元字符 相当于 \\b 匹配单词边界 ^ 字符串必须以指定的字符开始 $selectionnbsp; 字符串必须以指定的字符结束 说明 ( )由于在正则表达式中 \\ ? * ^ $ + ( ) | [ 等字符已经具有一定特殊意义 如果需要用它们的原始意义 则应该对它进行转义 例如希望在字符串中至少有一个 \\ 那么正则表达式应该这么写 \\\\+ ( )可以将多个元字符或者原义文本字符用括号括起来形成一个分组 比如^( )[ ]\\d $表示任意以 开头的移动号码 ( )另外对于中文字符的匹配是采用其对应的 Unicode编码来匹配的 对于单个Unicode字符 如\\u e 表示汉字 一 \\u fa 表示汉字 龥 在Unicode编码中这分别是所能表示的汉字的第一个和最后一个的Unicode编码 在Unicode编码中能表示 个汉字 ( )关于\\b的用法 它代表单词的开始或者结尾 以字符串 a b d 作为示例字符串 如果正则表达式是 \\b\\d \\b 则仅能匹配 ( )可以使用 | 来表示或的关系 例如 [z|j|q]表示匹配z j q之中的任意一个字母 正则表达式分组 将正则表达式的一部分用()括起来就可以形成一个分组 也叫一个子匹配或者一个捕获组 例如对于 : : 这样格式的时间 我们可以写如下的正则表达式 (( [ ])|( [ ])|( [ ])( [ ][ ]) 如果以这个作为表达式 它将从下面的一段IIS访问日志中提取出访问时间(当然分析IIS日志最好的工具是Log Parser这个微软提供的工具) : : GET /admin_save : : GET /userbuding asp : : GET /upfile_flash asp : : GET /cp php : : GET /sqldata php : : GET / : : GET /l 如果我们想对上面的IIS日志进行分析 提取每条日志中的访问时间 访问页面 客户端IP及端响应代码(对应C#中的HttpStatusCode) 我们可以按照分组的方式来获取
代码如下 private String text= @ : : GET /admin_save asp : : GET /userbuding asp : : GET /upfile_flash asp : : GET /cp php : : GET /sqldata php : : GET / : : GET /l ; /// <summary> /// 分析IIS日志 提取客户端访问的时间 URL IP地址及服务器响应代码 /// </summary> public void AnalyzeIISLog() //提取访问时间 URL IP地址及服务器响应代码的正则表达式 //大家可以看到关于提取时间部分的子表达式比较复杂 因为做了比较严格的时间匹配限制 //注意为了简化起见 没有对客户端IP格式进行严格验证 因为 IIS访问日志中也不会出现不符合要求的IP地址 Regex regex = new Regex(@ (( [ ]| [ ]| [ ])( [ ][ ]) )\\s(GET)\\s([^\\s]+)\\s(\\d (\\ \\d ) )\\s(\\d ) RegexOptions None) MatchCollection matchCollection = regex Matches(text) for (int i = ; i < matchCollection Count; i++) Match match = matchCollection[i]; Console WriteLine( Match[ ]======================== i) for (int j = ; j < match Groups Count; j++) Console WriteLine( Groups[ ]= j match Groups[j] Value) 这段代码的输出结果如下 Match[ ]======================== Groups[ ]= : : GET /admin_save asp Groups[ ]= : : Groups[ ]= Groups[ ]=: Groups[ ]=GET Groups[ ]=/admin_save asp Groups[ ]= Groups[ ]= Groups[ ]= Match[ ]======================== Groups[ ]= : : GET /userbuding asp Groups[ ]= : : Groups[ ]= Groups[ ]=: Groups[ ]=GET Groups[ ]=/userbuding asp Groups[ ]= Groups[ ]= Groups[ ]= Match[ ]======================== Groups[ ]= : : GET /upfile_flash asp Groups[ ]= : : Groups[ ]= Groups[ ]=: Groups[ ]=GET Groups[ ]=/upfile_flash asp Groups[ ]= Groups[ ]= Groups[ ]= Match[ ]======================== Groups[ ]= : : GET /cp php Groups[ ]= : : Groups[ ]= Groups[ ]=: Groups[ ]=GET Groups[ ]=/cp php Groups[ ]= Groups[ ]= Groups[ ]= Match[ ]======================== Groups[ ]= : : GET /sqldata php Groups[ ]= : : Groups[ ]= Groups[ ]=: Groups[ ]=GET Groups[ ]=/sqldata php Groups[ ]= Groups[ ]= Groups[ ]= Match[ ]======================== Groups[ ]= : : GET / Groups[ ]= : : Groups[ ]= Groups[ ]=: Groups[ ]=GET Groups[ ]=/ Groups[ ]= Groups[ ]= Groups[ ]= Match[ ]======================== Groups[ ]= : : GET /l Groups[ ]= : : Groups[ ]= Groups[ ]=: Groups[ ]=GET Groups[ ]=/l Groups[ ]= Groups[ ]= Groups[ ]= 从上面的输出结果中我们可以看出在每一个匹配结果中 第 个分组就是客户端访问时间(因为索引是从 开始的 所以索引顺序为 以下同理) 第 个分组是访问的URL(索引顺序为 ) 第 个分组是客户端IP(索引顺序为 ) 第 个分组是服务器端响应代码(索引顺序为 ) 如果我们要提取这些元素 可以直接按照索引来访问这些值就可以了 这样比我们不采用正则表达式要方便多了 命名捕获组 上面的方法尽管方便 但也有一些不便之处 假如需要提取更多的信息 对捕获组进行了增减 就会导致捕获组索引对应的值发生变化 我们就需要重新修改代码 这也算是一种硬编码吧 有没有比较好的办法呢?答案是有的 那就是采用命名捕获组 就像我们使用 DataReader访问数据库或者访问DataTable中的数据一样 可以使用索引的方式(索引同样也是从 开始) 不过如果变化了select语句中的字段数或者字段顺序 按照这种方式获取数据就需要重新变动 为了适应这种变化 同样也允许使用字段名作为索引来访问数据 只要数据源中存在这个字段而不管顺序如何都会取到正确的值 在正则表达式中命名捕获组也可以起到同样的作用 普通捕获组表示方式 (正则表达式) 如(\\d ) 命名捕获组表示方式 (?<捕获组命名>正则表达式) 如(?<phone>\\d ) 对于普通捕获组只能采用索引的方式获取它对应的值 但对于命名捕获组 还可以采用按名称的方式访问 例如(?<phone>\\d ) 在代码中就可以按照 match Groups[ phone ]的方式访问 这样代码更直观 编码也更灵活 针对刚才的对IIS日志的分析 我们采用命名捕获组的代码如下 private String text= @ : : GET /admin_save asp : : GET /userbuding asp : : GET /upfile_flash asp : : GET /cp php : : GET /sqldata php : : GET / : : GET /l ; /// <summary> /// 采用命名捕获组提取IIS日志里的相关信息 /// </summary> public void AnalyzeIISLog () Regex regex = new Regex(@ (?<time>( [ ]| [ ]| [ ])( [ ][ ]) )\\s(GET)\\s(?<url>[^\\s]+)\\s(?<ip>\\d (\\ \\d ) )\\s(?<Code>\\d ) RegexOptions None) MatchCollection matchCollection = regex Matches(text) for (int i = ; i < matchCollection Count; i++) Match match = matchCollection[i]; Console WriteLine( Match[ ]======================== i) Console WriteLine( time: match Groups[ time ]) Console WriteLine( url: match Groups[ url ]) Console WriteLine( ip: match Groups[ ip ]) Console WriteLine( match Groups[ Code ]) 这段代码的执行效果如下 Match[ ]======================== time: : : url: ip: Code: Match[ ]======================== time: : : url: ip: Code: Match[ ]======================== time: : : url: ip: Code: Match[ ]======================== time: : : url: ip: Code: Match[ ]======================== time: : : url: ip: Code: Match[ ]======================== time: : : url: ip: Code: Match[ ]======================== time: : : url: ip: Code: 采用命名捕获组之后使访问捕获组的值更直观了 而且只要命名捕获组的值不发生变化 其它的变化都不影响原来的代码 非捕获组 如果经常看别人有关正则表达式的源代码 可能会看到形如(? 子表达式)这样的表达式 这就是非捕获组 对于捕获组我们可以理解 就是在后面的代码中可以通过索引或者名称(如果是命名捕获组)的方式来访问匹配的值 因为在匹配过程中会将对应的值保存到中 如果我们在后面不需要访问匹配的值那么就可以告诉程序不用在内存中保存匹配的值 以便提高效率减少内存消耗 这种情况下就可以使用非捕获组 例如在刚刚分析IIS日志的时候我们对客户端提交请求的方式并不在乎 在这里就可以使用非捕获组 如下 Regex regex = new Regex(@ (?<time>( [ ]| [ ]| [ ])( [ ][ ]) )\\s(? GET)\\s(?<url>[^\\s]+)\\s(?<ip>\\d (\\ \\d ) )\\s(?<Code>\\d ) ; 零宽度断言 关于零宽度断言有多种叫法 也有叫环视 也有叫预搜索的 我这里采用的是MSDN中的叫法 关于零宽度断言有以下几种 (?= 子表达式) 零宽度正预测先行断言 仅当子表达式在此位置的右侧匹配时才继续匹配 例如 (?= ) 与跟在 前面的 实例匹配 (?! 子表达式) 零宽度负预测先行断言 仅当子表达式不在此位置的右侧匹配时才继续匹配 例如 (?! )与不以 结尾的单词匹配 所以不与 匹配 (?<= 子表达式) 零宽度正回顾后发断言 仅当子表达式在此位置的左侧匹配时才继续匹配 例如 (?<= ) 与跟在 后面的 的实例匹配 此构造不会回溯 (?<! 子表达式) 零宽度负回顾后发断言 仅当子表达式不在此位置的左侧匹配时才继续匹配 例如(?<= )与不以 开头的单词匹配 所以不与 匹配 正则表达式选项 在使用正则表达式时除了使用RegexOptions这个枚举给正则表达式赋予一些额外的选项之外 还可以在在表达式中使用这些选项 如 Regex regex = new Regex( (?i)def ) Regex regex = new Regex( (?i)def ) 它与下面一句是等效的 Regex regex = new Regex( def RegexOptions IgnoreCase) Regex regex = new Regex( def RegexOptions IgnoreCase) 采用(?i)这种形式的称之为内联模式 顾名思义就是在正则表达式中已经体现了正则表达式选项 这些内联字符与RegexOptions的对应如下 IgnoreCase:内联字符为i 指定不区分大小写的匹配 Multiline:内联字符为m 指定多行模式 更改 ^ 和 $ 的含义 以使它们分别与任何行的开头和结尾匹配 而不只是与整个字符串的开头和结尾匹配 ExplicitCapture:内联字符为n 指定唯一有效的捕获是显式命名或编号的 (?<name>…) 形式的组 这允许圆括号充当非捕获组 从而避免了由 (? …) 导致的语法上的笨拙 Singleline:内联字符为s 指定单行模式 更改句点字符 ( ) 的含义 以使它与每个字符(而不是除 \\n 之外的所有字符)匹配 IgnorePatternWhitespace:内联字符为x 指定从模式中排除非转义空白并启用数字符号 (#) 后面的注释 (有关转义空白字符的列表 请参见字符转义 ) 请注意 空白永远不会从字符类中消除 举例说明 RegexOptions option=RegexOptions IgnoreCase|RegexOptions Singleline; Regex regex = new Regex( def option) 用内联的形式表示为 Regex regex = new Regex( (?is)def ) 说明 其实关于正则表达式还有比较多的内容可以讲 比如反向引用 匹配顺序及几种匹配模式的区别和联系等 不过这些在日常开发中使用不是太多(如果做文本分析处理还是会用到的) 所以暂时不会继续讲了 尽管本系列四篇文章篇幅都不是太长(本人不敢太熬夜了 因为每天 点多就要起床) 不过通过这些基础的学习仍是可以掌握正则表达式的精华之处的 至于在开发中怎么样去用 就要靠我们自己灵活去结合实际情况用了 我个人经验是如果是用于验证是否满足要求 那么写正则表达式时写得严格一点 如果是从规范格式的文本中提取数据 则可以写得宽松一点 比如验证时间 则必须写成(?<time>( [ ]| [ ]| [ ])( [ ][ ]) )这种形式 这样别人输入 : : 就不能通过验证 但是如果是像从上面提到的IIS日志中提取时间 用 (?<time>\\d ( \\d ) )这种方式也是可以 当然如果写比较严格的验证比较麻烦时也可以写比较宽松的格式 然后借助其它手段来验证 在网上有一个验证日期的正则表达式 编写者充分考虑到各个月份天数的不同 甚至平年和闰年 月份天数的不同的情况写了一个相当复杂的正则表达式来验证 个人觉得可以结合将文本值转换成日期的方式来共同验证 这样更好理解和接受些 到此 关于正则表达式的文章就暂时写到这里了 其它还有一些知识用得不是太多 以后有时间再总结了 cha138/Article/program/net/201311/12785相关参考
正则表达式在PHP中的应用在PHP应用中正则表达式主要用于•正则匹配根据正则表达式匹配相应的内容•正则替换根据正则表达式匹配内容并替换•正则分割根据正则表达式分割字符串在PHP中有两类正则表达式函
很久没有遇上PHP难题了这次正则问题占了一点时间还是老问题最大回溯递归限制问题学习透之后其实并不难修改调试有这类问题的正则主要是以下几点 基于正则表达式替换的模板引擎很容易遇上正则表达式最大回溯
三括号或匹配 在正则表达式中由于[]号只能做单个元素的匹配这样会限制正则表达式的作用如何做到多个元素的匹配呢?用()实现 ()可以进行多个元素的匹配例如:t(a|e|i|o|oo)n|在正则表
PHP和正则表达式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一个正则表达式是一个特定的格式
简单的说正则表达式是一种可以用于模式匹配和替换的强有力的工具我们可以在几乎所有的基于UNIX系统的工具中找到正则表达式的身影例如vi编辑器Perl或PHP脚本语言以及awk或sedshell程序等
PHP正则表达式基本函数 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在PHP正则表达式中需要
C#正则表达式整理备忘(1) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 有一段时间正则表达式
PHP正则表达式使用的方法 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! PHP正则表达式主要用
C#正则表达式整理备忘(2) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! ()择一匹配C#正则