[b]正则表达式的特性和流派[/b]
经过前面的介绍,我们大概见识了正则表达式的样子,也见识了若干使用正则表达式的工具软件,工具不同正则表达式的写法和用法都有很大的不同。
在特定的宿主语言或工具软件中使用正则表达式时,主要有[b]3个问题值得注意[/b]:
[b]1.支持的元字符[/b],以及这些元字符的意义。这通常称为正则表达式的[color=red]“流派(flavor)”[/color]。
2.正则表达式与语言或工具的[b]交互方式[/b]。譬如如何进行正则表达式操作,容许进行哪些操作,以及这些操作的目标文本类型。
3.[b]正则表达式引擎[/b]如何将表达式应用到文本。语言或工具的设计者实现正则表达式的方法,对正则表达式能够取得的结果有重要的影响。

关于正则表达式的起源和发展历程,感兴趣的大家可以查看《精通正则表达式》的第三章。

[b]3.1正则表达式的注意事项和处理方式[/b]
在使用正则表达式之前首先要清楚使用的工具支持的元字符,然后就是正则表达式的句法规则,它告诉应用程序如何去做。egrep是一个简单的例子,因为正则表达式是作为命令行参数传过去的。复杂系统,例如程序设计语言中的正则表达式,需要更多的包装,系统才能知道哪些部分是正则表达式,需要如何处理。
下一步是考察我们能够对匹配结果进行的操作。其中最基本的是匹配(检查一个正则表达式是否能匹配一个字符串,或从字符串中提取信息),以及查找和替换,根据匹配的结果修改字符串。

一般来说,程序设计语言有3种处理正则表达式的方式:[b]集成式(integrated),程序式(procedural)和面向对象式(object-oriented)[/b]。第一种方式中,正则表达式直接内建在语言之中,perl,awk就是这样。其他两种方式中,正则表达式不属于语言的低级语法。大多数语言采用的都是这两种方式之一,包括java,.NET,TCL,python,ruby等。

[b]3.2字符串,字符编码和匹配模式[/b]
在深入讲解常见的各类元字符之前,还需要了解一些重要的问题:[color=red]作为正则表达式的字符串,字符编码和匹配模式[/color]。
这些概念并不复杂,在理论和实践中都是如此,不过,对其中的大多数来说,因为各种实现方式之间存在细小差异,我们很难预先知道他们准确的实际使用方式。

[b]3.2.1 作为正则表达式的字符串[/b]
对[b]除[/b]perl,awk,sed之外的大多数语言来说,正则引擎接收的是以[b]普通字符串形式[/b]提供的正则表达式,这些字符串类似”^From: (.*)”。对程序员来说,在构造作为正则表达式的字符串时,还需要留意编程语言定义的字符串元字符。如java反斜线”\”要转义”\\”才行,单词分界符”\b”要写成\\b才行。
每种语言的字符串文字都规定了自己的元字符,有些语言甚至包含了多种字符串文字,所以不存在普适性的规则。

[b]3.2.2 字符编码[/b]
字符编码是一种写明的共识,它规定不同数值的字节应该如何解释。在ASXII编码中,值为十进制的110的字节代表字符’n’,不过在EBCDIC编码中代表’>’。 字节的值是一样的,但解释不一样,因为这是由不同的人规定的,没有明确的标准判断各种编码的优劣。

对我们来说,重要的问题在于,如果我们期望使用某种特定编码的数据,程序是否会这样做。例如,我们使用Latin-1编码值为234,116,101和115的4个字节表示法语单词”Ê tes”,我们期望正则表达式”^\w+$”或”^\b”来匹配,如果程序中的\w或\b能支持Latin-1字符,就可以正常工作,否则不行。[b]这取决于语言中正则表达式对编码的支持程度[/b]。

[b]3.3 正则模式和匹配模式[/b]
许多正则引擎都支持多种不同的模式,他们规定了正则表达式应该如何解释和应用。比如perl的”/i”修饰符不区分大小写匹配的模式。
许多流派中,模式可以完全作用于整个表达式,也可以单独作用于某个子表达式。整体应用时通过修饰符或者选项来决定的,如perl的/i或java.util.regex的Pattern.CASE_INSENSITIVE标志。如果语言支持的话,应用到目标字符串中部分文本的模式是通过一个正则结构来实现的。如”(?i)”来开启不区分大小写的模式,”(?-i)”来停用该匹配。

注意,不同的语言,对模式使用的语法是不一样的。
[b]1.不区分大小写匹配模式[/b]
此模式很常见,它在匹配过程中会忽略字母的大小写。此功能也必须依赖于正确的字符编码支持。

[b]2.宽松排列和注释模式[/b]
此模式会忽略字符组外部的所有空白字符。字符组内部的空白字符仍然有效(java.util.regex是例外)。#符号和换行符之间的内容视为注释。
在java.util.regex中,字符组之外的所有空白字符并非都会被忽略,而是作为一个“无意义元字符”。在理解”\12 3”时,这种区分很重要,因为它表示”3” 接在“\12”后面,而不是忽略空格”\123”。
当然,空白字符的定义取决于所采用的字符编码的定义,以及此编码对空白字符的支持程度。大多数程序只能识别ASCII的空白字符。

[b]3.点号通配符(也叫单行模式)[/b]
前面我们说过正则的元字符点号(.)能代表所有字符,[b]但通常点号是不能匹配换行符的[/b]。这是匹配模式的差别。通常,能够处理多行文本的工具(如文本编辑器)通常不容许点号匹配换行符。
对现代编程语言来说,点号能够匹配换行符的模式和不能匹配的模式同样有用。这两种模式哪个更方便,取决于具体的情况。许多程序提供了两种方法供正则表达式选择。

[b]4.不幸的命名[/b]
/s修饰符对应的匹配模式第一次出现在perl时被称为单行文本模式。其实单行文本模式指的是点号不受限制,可以匹配任何字符。

[b]5.增强的行锚点模式(也叫多行文本模式)[/b]
多行文本模式会影响到行锚点”^”和”$”的匹配。通常情况下”^”不能匹配字符串[b]内部的换行符[/b],而只能匹配目标字符串的起始位置。但是在多行文本模式下,它能匹配字符串中内嵌的文本行的开头位置。
“$”也是这样,在多行文本模式下可以匹配字符串内部的换行符。

[b]6.文字文本模式[/b]
“文字文本(literal text)”模式几乎不能识别任何正则表达式元字符。例如,文字文本模式下”[a-z]*”匹配字符串”[a-z]*”,而不是搜索这个正则表达式。支持正则表达式的程序通常也提供了普通的字符串搜索功能。

[b]3.4 常用的元字符和特性[/b]
下面介绍下常见正则表达式元字符和概念。这里的介绍并不是全面彻底的,不过也没有任何一种正则工具涉及其中的所有内容。[b]使用时最好参考使用的工具提供的使用手册[/b]。

[b]3.4.1 字符表示法[/b]
这一组元字符能够以清晰美观的方式匹配其他方式中很难描述的某些字符。
[b]1.字符缩略表示法[/b]
许多工具软件提供了某些控制字符的元字符,其中有一些在所有机器上都是不变的,但也有些很难输入或观察。
[img]http://dl2.iteye.com/upload/attachment/0094/9659/d792ea2a-c229-33a7-bfeb-1f985ca41e5a.bmp[/img]

在许多工具中,[b]\n和\r的意义是随操作系统的变化而变化的[/b],所以在使用时应该格外小心。如果需要在程序可能运行的[color=red][b]所有平台上都能通用的换行符,请使用\n[/b][/color]。

[b]3.4.2 字符组及相关结构[/b]
在许多流派中,都有多种方法在正则表达式的某个位置指定一组字符,不过最通行的方法还是使用普通字符组。

[b]1.普通字符组[a-z]和[^a-z][/b]
我们已经介绍过字符组的基本概念,不过还要强调,元字符的规定在字符组内外是有差别的。如,在字符组内部”*”永远不是元字符,而”-”通常都是元字符,但如果在字符组内是第一个字符就不是元字符。
[color=red]在大多数系统中,[/color][b]字符组内部的顺序是无关紧要的[/b],而且使用范围表示法而不是列出范围内的所有字符[b]并不会影响执行速度[/b](例如,[0-9]与[0123456789]是一样的)。相反,某些实现方式不能完全优化字符组(比如sun提供的java regex package),所以[color=red][b]最好是使用范围表示法[/b][/color],因为如果有差别,这种表示法速度会快一些。

字符组通常表示肯定断言。也就是说,他们必须匹配一个字符。排除型字符组仍然需要匹配一个字符,只是他没有在字符组中列出而已。把排除型字符组理解为“匹配一个未列出的字符的字符组”或许更容易理解一些。

[b]2.几乎能匹配任何字符的元字符:点号[/b]
在某些工具软件中,点号用来缩略表示可以匹配任何字符的字符组,而在其他工具中,点号能匹配除了换行符之外的任何字符。
[b]1)在sun的java regex package之类的支持unicode的系统中,点号不能匹配unicode的终结符。
2)匹配模式(单行模式还是多行模式)会改变点号的匹配规则。
3)posix规定,点号不能匹配NUL(值为0的字符),尽管大多数脚本语言容许文本中出现NULL(而且可以用点号来匹配)。[/b]

[b]3.点号,还是排除型字符组[/b]
如果所使用的工具能够在多行文本中搜索,请务必注意点号,它在通常情况下不能匹配换行符,而排除型字符组”[^"]”通常可以。

[b]4.字符组简记法: \w,\d,\s,\W,\D,\S[/b]

[img]http://dl2.iteye.com/upload/attachment/0094/9663/7c45b135-cd58-3402-904c-c63647c912c1.bmp[/img]

[b]5. 完整的字符组集合运算:[[a-z] && [^aeiou]][/b]
sun的java regex package 中的字符组能够进行完整的集合运算(交集,并集,差集)。
并集:[abcxyz]也可以表示为[[abc][xyz]],或[abc[xyz]]或[[abc]xyz]
交集:[this && [^that]]表示[this]减去[that]。

[b]3.4.3锚点和其他“零长度断言”[/b]
[color=red][b]锚点(^,$)和其他“零长度断言”并不会匹配实际的文本,而是寻找文本的位置。[/b][/color]
[b]1.行/字符串的起始位置:^, \A[/b]
脱字符”^”匹配需要搜索的文本的起始位置,如果使用了增强的行锚点匹配模式(多行模式),它还能匹配每个换行符之后的位置。在某些系统中,增强模式下”^”还能匹配Unicode的行终结符。
如果可以使用,则无论在什么匹配模式下,”\A”总是能够匹配待搜索文本的起始位置。

[b]2.行/字符串结束位置:$, \Z和\z[/b]
“行结束位置”的概念比行开头位置更复杂。在不同的工具软件中,$的意义也不同,不过最[b]常见的意思是匹配字符串的末尾[/b]。也可以匹配整个字符串末尾的换行符之前的位置。比如”s$”匹配s结尾的行,有时也可以匹配以s和换行符结尾的行。
$的[b]另两种常见的意思是,只匹配目标文本的结束位置,或是匹配任何一个换行符之前的位置[/b]。在某些Unicode系统中,这些规则中的换行符会被替换为Unicode的行终结符(java为了处理Unicode中的行终结符,为$设定了非常复杂的语义)。
匹配模式可以改变”$”的意义,匹配字符串中的任何换行符(或者是Unicode的行终结符)。

如果支持,”\Z”通常表示”未指定任何模式下”$匹配的字符,通常是字符串的末尾位置,或者是在字符串末尾的换行符之前的位置。作为补充,”\z”只匹配字符串的末尾,而不考虑任何换行符。

[b]3.匹配的起始位置(或者是上一次匹配的结束位置):\G[/b]
“\G”首先出现在perl中,在使用/g的匹配中,\G对地带操作非常有用。它能匹配上一次匹配结束的位置。在一次迭代时,”\G”匹配字符串的开头,和\A一样。
如果匹配不成功,”\G”的匹配会重新指向字符串的起始位置。这样,如果重复应用某个正则表达式,例如进行perl的”s/…/…/g”操作,在匹配失败的同时,”\G”也会指向字符串的开头位置,这样以后进行其他类型的匹配操作便不受影响。关于\G更详细的用法,请参考对应语言的说明。

[b]4.单词分界符:\b,\B,\<,\>…[/b]
单词分界符的作用与行锚点一样,也是匹配字符串中的某些位置。单词分界符可以分为两类,一类中单词起始位置分界符和结束位置分界符是不相同的(通常是\<和\>),另一类则以统一的分界符来匹配(通常是\b)。两类都提供了非单词分界符(通常是\B)。
[b]单词分界符通常可以这样理解,这个位置的以便是“单词字符”,另一边不是。[/b]

[b]5.顺序环视(?=…),(?!...)和逆序环视(?<=…), (?<!...)[/b]
在前面“使用环视功能在数值中插入逗号”的例子中,我们介绍过顺序环视和逆序环视结构(统称环视)。但关于他们还有很重要的一点没有讲,那就是环视结构中能够出现什么样的表达式。大多数实现方式都限制了逆序环视中的表达式的长度(但是顺序环视则没有限制)。
perl和python的限制是最严格的,逆序环视只能匹配固定长度的文本。使用(?<!\w)和(?<!this|that)不会出错,但是(?<!books?)和(?<!^\w+:)则不行,因为他们匹配的文本的长度是不确定的。

[b]3.5 注释和模式修饰符[/b]
在许多流派中,使用下面的结构,就能够在正则表达式内部,切换使用之前介绍的正则表达式模式和匹配模式。

[b]3.5.1 模式修饰符: (?modifier),例如(?i)和(?-i)[/b]
[b]现在许多流派容许正则表达式中设定匹配模式[/b]。最常见的就是(?i),它会启用不区分大小写的匹配,而(?-i)会停用此功能。例如”<B>(?i)very(?-i)</B>”会对中间的very进行不区分大小写的匹配。而两端的tag仍然必须大写。
这个例子在大多数系统中可以运行,例如perl,PHP,java.util.regex,ruby和.net可以。在python和tcl中不行,他们不支持。
模式修饰符中能够出现的不只有i。大多数系统中,我们至少可以使用下面列出的修饰符,有些系统还提供了更多的选项。

[b]3.5.2 模式作用范围: (?modifier:…),例如(?i:…)[/b]
如果所使用的系统支持模式修饰范围,这样使用起来就更加简化。”(?i:…)”表示模式修饰符的作用范围只有在括号内有效。这样”<B>(?i)very(?-i)</B>”就可以简化为”<B>(?i:very)</B>”。
[img]http://dl2.iteye.com/upload/attachment/0094/9661/32a67cdd-35de-36cb-af82-ef2c98167336.bmp[/img]

[b]3.5.3 注释: (?#...)和#...[/b]
某些流派支持用”(?#...)”添加注释。实际上,如果流派支持宽松排列和注释模式,就很少使用这种功能。不过,如果在字符串文字中很难插入换行符,用这种格式加入注释就非常方便。

[b]3.5.4 文字文本模式: \Q…\E[/b]
\Q…\E是由perl引入的,它会消除其中除\E之外所有元字符的特殊含义(如果没有\E,就会一直作用到正则表达式末端)。其中的所有字符都会被当成普通文字文本来对待。如果在构建正则表达式时包含变量,此功能就非常有用。
目前支持”\Q…\E”的引擎只有java.util.regex和pcre(包括PHP的preg套件)。在低于1.6的java中,对这个模式的支持是不可靠的,不建议使用。

[b]3.6 分组,捕获,条件判断和控制[/b]
[b]3.6.1 捕获/分组括号: (…)和\1,\2,…[/b]
普通的[b]无特殊意义的括号通常有两种功能:[/b][b]分组和捕获[/b]。普通括号常见的形式是”(…)”,但有的流派中使用”\(…\)”,例如sed,vi和grep.
捕获型括号的编号是按照开括号出现的次序,从左到右计算的。如果提供了反向引用,则这些括号内的子表达式匹配的文本可以在表达式后面部分用\1,\2来引用。
括号的常用功能之一是从字符串中提取数据。括号中的子表达式匹配的文本在不同的程序中可以通过不同的方式引用。如perl用$1,$2引用。

[b]3.6.2 仅用于分组的括号: (?:…)[/b]
仅用于分组的括号不能用来提取文本,而只能用来规定多选结构或量词的作用对象。他们不会按照$1,$2之类编号。匹配的性能要比捕获型括号高。仅用于分组的括号也称为非捕获型括号。

[b]3.6.3 固化分组: (?>…)[/b]
如果详细了解正则引擎的匹配原理(后面会介绍),就很容易理解固化分组。就是一旦括号内的子表达式匹配之后,匹配的内容就固定下来,在接下来的匹配过程中也不会变化,除非整个固化分组的括号都被弃用,在外部回溯中重新应用。

比如,”i.*!”能够匹配”iHola!”,但是如果”.*”在固化分组中”i(?>.*)!”就无法匹配。因为”.*”会尽可能多的匹配内容,直到匹配的最后的”!”,如果固化分组了,它匹配后不会交还”!”,导致正则表达式最后的”!”无法匹配。

[b]3.6.4 多选结构: …|…|…[/b]
多选结构能在同一个位置测试多个子表达式。每个子表达式称为一个多选分支(alternative)。多选结构的优先级很低,所以”this and|or that”的匹配等价于”(this and|(or that))”,而不是”this (and|or) that”

[b]3.6.5 条件判断: (?if then | else)[/b]
这个结构允许用户在正则表达式中使用if/then/else判断。如果if部分为真,则尝试then的表达式,否则尝试else部分(else部分可以不出现)。
if的种类因流派的不同而不同,但是大多数实现方式都容许在其中引用捕获的子表达式和环视结构。

[b]3.7 量词[/b]
[b]3.7.1 匹配优先量词: *,+,?,{min, max}[/b]
量词(星号,加号,问号,以及区间元字符)能够限制作用对象的匹配次数。匹配优先就是[color=red]尽可能多[/color]的匹配符合要求的内容。

[b]3.7.2 忽略优先量词: *?,+?,??,{min,max}?[/b]
我们发现在匹配优先量词后面都加了个问号,这样就成了忽略优先量词,他们会[color=red]尽可能少[/color]的匹配内容,只需要满足下限就成功。

[b]3.7.3 占有优先量词: *+, ++, ?+, {min,max}+[/b]
这些量词就是在匹配优先量词后面加个了加号,目前只有java.util.regex和pcre提供。占有优先量词[color=red]类似普通的匹配优先量词[/color],不过他们一旦匹配某些内容,就[color=red]不会”交还”[/color]。[b]这点有点类似固化分组。[/b]后面介绍匹配原理时就很容易理解他的含义了。

基础-3 正则的特性和流派相关推荐

  1. [.net 面向对象编程基础] (13) 面向对象三大特性——多态

    [.net 面向对象编程基础] (13) 面向对象三大特性--多态 前面两节,我们了解了面向对象的的封装和继承特性,面向对象还有一大特性就是多态.比起前面的封装和继承,多态这个概念不是那么好理解.我们 ...

  2. polymorphism java_Java基础-面向对象第三大特性之多态(polymorphism)

    Java基础-面向对象第三大特性之多态(polymorphism) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.多态概述 多态是继封装,继承之后,面向对象的第三大特性,多态的 ...

  3. Java基础之Java8 新特性

    hp实训8.19_Java基础之Java8新特性 // 信息展示方法 ,接口中,就可以提供一种实现. 就可以使用这种功能.default void print() {System.out.printl ...

  4. 精通正则表达式第三章:正则表达式的特性和流派概览

    程序设计语言处理正则表达式的方式 集成式:表达式直接内建在语言之中,如Perl 程序式和面向对象式:正则表达式不属于语言的低级语法.相反,普通的函数接受普通的字符串,把他们作为正则表达式进行处理. 集 ...

  5. Redis基础用法、高级特性与性能调优以及缓存穿透等分析

    目录 一.Redis介绍 二.Redis数据结构及常用的命令 三.Redis持久化策略选择 四.内存管理与数据淘汰机制 五.Redis过期策略及实现原理 1  说明 2  设置过期时间 3  三种过期 ...

  6. 【Python基础】Python高级特性:切片、迭代、列表生成式、生成器与迭代器

    接着廖雪峰老师的学习教程,小编要开始加快推进Python的学习进程了.今天的笔记内容是Python高级特性,其中包括快速访问对象类型元素的切片.循环中的迭代意义.方便的列表生成式操作以及生成器和迭代器 ...

  7. bash初识,shell的基础语法及基本特性

    1.1 bash初识 1.1.1 什么是bash shell 是一个命令解释器,负责用户程序与内核进行交互操作的一种接口, 将用户输入的命令翻译给操作系统,并将处理后的结果输出至屏幕. 1.1.2 b ...

  8. 01_Go语言基础学习_Golang语言特性、环境搭建、第一个Go程序、包

    1. Golang语言特性: 垃圾回收: 1.内存自动回收,再也不需要开发人员管理内存: 2.开发人员专注业务实现,降低了心智负担 : 3.只需要new分配内存,不需要释放 天然并发: 1.从语言层面 ...

  9. Java基础语法96-Java91011新特性

    Java基础语法96-Java9&10&11新特性 一.java9新特性 一. JDK 和 JRE 目录结构的改变 bin 目录 包含命令行开发和调试工具,如javac,jar和jav ...

最新文章

  1. 可视化生信分析利器 Galaxy 之 Docker 部署
  2. KDE发布四月份更新(4.6.2),与GNOME同祝
  3. erp服务器哪个稳定,选择erp服务器需要注意的几大问题
  4. 03-kubeadm初始化Kubernetes集群
  5. Git学习系列(六)解决分支冲突及分支管理策略
  6. Spark编译报错问题日志记录
  7. mysql 去重后拼接_mysql学习笔记(三)—— 查询select
  8. 高考改变命运,来自一个湖南贫困村的真实样本
  9. k3s,k9s harbor https
  10. 视频教程-微信公众号编辑器开发-微信公众号开发11-微信开发php-微信开发
  11. 为什么阿里巴巴规定禁止超过三张表 join
  12. 域名 CN 被注册;上世纪最大的 BBS 论坛 | 历史上的今天
  13. Vue知识点总结(一)
  14. 高盐废水如何处理,离子交换树脂在高盐废水中的应用
  15. 微信小程序原生表格组件
  16. Golang学习系列第六天:操作MongoDB
  17. 基于python的鲜花商城
  18. 如果你看见这个舞女是顺时针转,说明你用的是右脑;耶鲁大学耗时5年的研究成果。左脑?右脑?
  19. index函数用法python_python中的index函数 Python中的index一般是什么意思,怎么个用法?...
  20. Deep Interest Network

热门文章

  1. 嵌入式系统:后PC时代的擎天之柱!!!
  2. 【小强推歌】---音乐从今天开始
  3. 如何在word中插入c、java等风格的代码
  4. 我的世界java如何做鬼畜沙_我的世界:到底是特性还是游戏bug?沙子开始鬼畜闪动...
  5. 如果用户希望将自己计算机中的照片,信息技术会考模拟题共31套的选择三
  6. 编码为H264裸流并写文件一
  7. HTPC知识普及讲座之六 全套设备的组建1
  8. C#工厂模式-简单工厂模式
  9. 数据库各章节自测题以及答案
  10. 2020年824计算机辅助制造,824计算机辅助制造-第三章.docx