正则表达式学习3

2.“或”匹配

  有的时候,我们要取消某段文字中的加粗、斜体等效果,我们想匹配所有的“<b>”、“</b>” 或者 “<i>”、“</i>”,然后把它们替换成空,仅利用之前的知识,我们只能

进行两次匹配和替换,一次是“</?b>”,一次是“</?i>”。

      在正则表达式中,可以使用“|”将一个表达式拆分成两部分“reg1|reg2”,它的意思是:匹配所有符合表达式reg1的文本 或者 符合表达式reg2的文本。

对于本节提出的问题,可以这样进行解决:

Text

  The <b>text of</b> this row is bold.

  The <i>text of</i> this row is italic.

RegEx

  </?i>|</?b>

Result

  The <b>text of</b> this row is bold.

  The <i>text of</i> this row is italic.

3.在子模式中使用“或”匹配

  从上面的定义应该可以看出,“|”分隔的是整个表达式,而有的时候,我们希望分隔的是一个表达式的一部分,比如说,我们想要匹配 “1900”到“2099”的所有年份。

Text

  1932 is supposed to be matched as a whole, but it is matched only part of it.

  2055 is mathced in the right way.

  3019 is out of range, but it's still matched partly.

RegEx

  19|20\d{2}

Result

  1932 is supposed to be matched as a whole, but it is matched only part of it.

  2055 is mathced in the right way.

  3019 is out of range, but it's still matched partly.

可以看到,表达式“19|20\d{2}”要么匹配“19”,要么匹配“20\d{2}”。而我们希望的是匹配“19\d{2}”或者“20\d{2}”,当然,我们可以改写上面的表达式为“19\d{2}

|20\d{2}”来完成,但是,利用本章所讲述的子模式,可以更加简洁地完成这个过程。

Text

  1932 is supposed to be matched as a whole, but it is matched only part of it.

  2055 is mathced in the right way.

  3019 is out of range, but it's still matched partly.

RegEx

  (19|20)\d{2}

Result

  1932 is supposed to be matched as a whole, but it is matched only part of it.

  2055 is mathced in the right way.

  3019 is out of range, but it's still matched partly.

  这次,我们得到了想要的结果,使用子模式可以简化匹配表达式。

  NOTE:有点类似于数学中的提取公因式:2*3 + 7*3 = (2+7)*3 --> 19\d{2}|20\d{2} = (19|20)\d{2}

4.嵌套子模式

  子模式可以再继续嵌套子模式,产生更加功能强大的匹配能力。比如,我们要匹配 1900年1月1日 到 2000年1月1日 除过闰年外的所有正确日期。

  我们先对这个匹配模式做一个分析:

  1. 首位可以是19也可以是20; Reg:19|20

  2. 当是19的时候,后面可以是00到99中任意数字; RegEx:19\d{2}|20

  3. 当是20的时候,只能匹配00; Reg:19\d{2}|2000

  4. 月份可以是1到9,或者10到12;Reg:(19\d{2}|2000)-([1-9]|1[0-2])

  因为天数与月份相关,所以将 ([1-9]|1[0-2]) 拆分为下面三个子模式:

  5. 当月份是2的时候,天数是28; Reg:2-([1-9]\b|1\d|2[0-8])

  6. 1、3、5、7、8、10、12月,天数是31; Reg:([13578]|1[02])-([1-9]\b|[12]\d|3[01])

  7. 4、6、9、11月,天数是30; Reg:([469]|11)-([1-9]\b|[12]\d|30)

  NOTE:注意上面日期部分的匹配,分成了两部分,月和日;对于月来说,如果我们要匹配大月(31天的月),写法是:[13578]|1[0-2];而日期部分,比如说要匹配31天,

它又由三部分组成:[1-9]表示1号到9号;[12]\d表示10号到29号;3[01]表示30号到31号。

  还有个地方需要注意:单词边界问题,如果你这样写表达式:2-([1-9]|1\d|2[0-8]),对于2-29 这样不应该匹配的日期,会匹配它合法的部分 2-29,因为2-2满足2-[1-

9]。回顾下我之前讲述的内容,我们还必须规定,当天数是个位数时,它必须处于单词边界[1-9]\b。

  组合一下,得到的月份和天数的模式是:

  2-([1-9]\b|1\d|2[0-8])|([13578]|1[02])-([1-9]\b|[12]\d|3[01])|([469]|11)-([1-9]\b|[12]\d|30)

  再结合上面年的部分,得到最终的结果:

  (19\d{2}|2000)-(2-([1-9]\b|1\d|2[0-8])|([13578]|1[02])-([1-9]\b|[12]\d|3[01])|([469]|11)-([1-9]\b|[12]\d|30))

Text

  These dates are matched: 1900-1-1、1928-2-28、1931-11-30、2000-1-1、1999-10-30

  These dates are not matched: 1900-1-32、1928-2-29、2000-01-1、1982-12-08

RegEx

  (19\d{2}|2000)-(2-([1-9]\b|1\d|2[0-8])|([13578]|1[02])-([1-9]\b|[12]\d|3[01])|([469]|11)-([1-9]\b|[12]\d|30))

Result

  These dates are matched: 1900-1-11928-2-281931-11-302000-1-11999-10-30

  These dates are not matched: 1900-1-32、1928-2-29、2000-01-1、1982-12-08

后向引用

 1.理解后向引用

  我们还是一如既往地从最简单的开始。假设我们要进行这样一个匹配:找出下面文本中所有重复的单词,以便日后进行替换。

  Is the cost of of gasline going up?

我们看到:“of of”重复了,我们需要找出它:

Text

  Is the cost of of gasline going up?

RegEx

  of of

Result

  Is the cost of of gasline going up?

  很显然,匹配结果满足了我们的要求,在这里使用全字匹配是为了后面好说明。

  现在,如果 up 也重复出现了,句子变成这样:

  Is the cost of of gasline going up up?

  我们就需要改写表达式成这样:

Text

  Is the cost of of gasline going up up?

RegEx

  (of|up) (of|up)

Result

  Is the cost of of gasline going up up?

  NOTE:我们可以使用更简洁的表达式:((of|up)\b ??){2},但是为了后面好说明,这里我们还是使用全字匹配。

  关于这个表达式,首先记住,\b只是对边界进行限制,不匹配任何字符。

  如果写做((of|up)\b ){2},则无法匹配“up up”,因为它要求up后面必须出现一个空格“ ”,而本句中,up后面紧跟了一个问号;

  如果写成((of|up)\b ?){2},因为是贪婪匹配,如果of后出现空格,就会匹配之。两个of的匹配将变成“of of ”。通常,我们会替换它成一个“of”,这样,就会出现

“ofgasline”的情况。

  最终,我们把贪婪匹配改成惰性匹配:((of|up)\b ??){2}

  可以看到,对这个句子来说,这样匹配没有问题。但是我们匹配的文本往往比这个复杂,让我们给上面的文本再添一句话。  

Text

  Is the cost of of gasline going up up?

  Look up of the TV, your mobile phone is there.

RegEx

  (of|up) (of|up)

Result

  Is the cost of of gasline going up up?

  Look up of the TV, your mobile phone is there.

  不幸的是,对于下面不应该匹配的“up of”也进行了匹配。而我们需要的是这样一种匹配:当前面是“of”的时候,后面跟的也是“of”;当前面是“up”时,后面跟的也是

“up”,只有这样的情况才去匹配它。换言之,后面所需要匹配的内容是前面的一个引用。

  正则表达式中,使用“\数字”来进行后向引用,数字表示这里引用的是前面的第几个子模式。

  我们回头在看本节第一个例子,我们也可以这样写:

Text

  Is the cost of of gasline going up?

RegEx

  (of) \1

Result

  Is the cost of of gasline going up?

  这里,表达式“(of) \1”使用了后向引用,意思是:“\1”代表前面第一个匹配了的子模式的内容,对于本例,因为前面子模式只可能匹配“of”,那么“\1”等价于“of”,整个

表达式相当于“of of”。

  现在,我们使用后向引用,对刚才出现“up of”问题的表达式加以纠正:

Text

  Is the cost of of gasline going up up?

  Look up of the TV, your mobile phone is there.

RegEx

  (of|up) \1

Result

  Is the cost of of gasline going up up?

  Look up of the TV, your mobile phone is there.

  这一次,我们获得了预期的效果,“(of|up) \1”的含义是:如果前面 子模式1 匹配了“of”,那么“\1”就代表“of”;如果 子模式1 匹配了 “up”,那么“\1”就代表

“up”,整个表达式相当于“of of|up up”。

posted @ 2012-04-02 22:20  烁星  阅读(292)  评论(0编辑  收藏  举报