Groovy Tip 29 正则表达式 三

来源:互联网 发布:淘宝店铺托管怎么收费 编辑:程序博客网 时间:2024/04/29 12:12

                       Groovy Tip 29  正则表达式 三

 

 

本篇主要来谈谈"捕获组"和"非匹配组"以及与它们相关联的一些概念。

"捕获组"应该来说是一个很重要的特性,特别是在进行文字处理的时候。比如,我们经常会遇到一些文字或数字跟一些符号混合在一起,而我们需要把这些文字或数字从这些符号中分离出来。这时候,我们就可以用到"捕获组"。

先从一个简单的例子说起。比如,我们有如下的一个email地址:

fgp@sina.com

 

我们需要从上面的email地址中分离出"fgp"、"sina"和"com"来,如果使用"split"方法的话,我们需要做两次"split"动作才能达到我们的要求。

但是,如果使用"捕获组"的话,我们只需要做一次动作。如:

 

      def amail = 'fgp@sina.com'

     

      def re = /(.*)@(.*)/.(.*)/

     

      def matcher = (amail =~ re)

     

      println matcher[0]

   

运行结果为:

["fgp@sina.com", "fgp", "sina", "com"]

 

再举一个看起来有那么一点点实用的例子,比如我们有如下的一组价格表,由商品名称、价格以及它们所能打的折扣组成。

computer 3000¥ 10%

mouse 50¥ 0%

memory 200¥ 20%

 

现在,我们希望把商品名称、价格和打折分别提取出来。

使用"捕获组"的代码如下:

 

      def goods =

"""computer 3000¥ 10%

mouse 50¥ 0%

memory 200¥ 20%"""

     

      def groups = {

             def re = /(.*) (.*)¥ (.*)%/

            

             def matcher = (it =~ re)

            

             println matcher[0]

      }

     

      goods.split('/n').each(groups)

   

 

运行上述代码的结果为:

["computer 3000¥ 10%", "computer", "3000", "10"]

["mouse 50¥ 0%", "mouse", "50", "0"]

["memory 200¥ 20%", "memory", "200", "20"]

 

 

相比较而言,"非匹配组"的使用就更为复杂一些,这里面除了"非匹配组"本身的概念,还有一些相关的概念需要说明。

首先要说明的是"最大匹配"和"最小匹配"的概念。在正则表达式中,我们的一些操作符,如"?"、"*"和"+"在默认的情况下,都是指的"最大匹配";如果需要需要"最小匹配",则需要在上述操作符后面加上"?"操作符,才能表示它们是"最小匹配"。

下面来举一个经典的例子来说明。比如我们有如下的一个html语句:

<td>abc</td>

 

那么,我们先进行如下的配置:

 

      def html = '<td>abc</td>'

     

      def re = /<.*>/

        

      def matcher = (html =~ re)

        

      println matcher[0]

   

 

再进行如下的匹配:

 

          def html = '<td>abc</td>'

        

         def re = /<.*?>/

            

          def matcher = (html =~ re)

            

         println matcher[0]

   

 

其中,第一段代码就进行的就是"最大匹配",运行结果为:

<td>abc</td>

 

第二段代码为"最小匹配",运行结果为:

<td>

 

所谓"非匹配组",指的是在一个字符串里,有我们想要的匹配组,也有我们不想要的非匹配组。我们想要的匹配组好说,就是使用我们上面所说到的"捕获组"来解决;那么我们不想要的非匹配组,我们该怎么处理呢?

要匹配"非匹配组",我们要做的工作其实是很简单,就是括号,并且在括号里以"?:"开头。下面来举一个例子说明。

还是以上面的价格表为例,比如我们有如下的价格表:

computer Intel CUP 3000¥ 10%

mouse made in China mainland 50¥ 0%

memory made in Taiwan 200¥ 20%

 

这个价格表比前面的价格表更为复杂一些,中间夹杂了一些对商品的描述。现在,我们还是希望取出商品名称、价格和打折来,而不需要商品的描述。

这样,我们就用到了"非匹配组",代码如下:

 

      def goods =

"""computer Intel CUP 3000¥ 10%

mouse made in China mainland 50¥ 0%

memory made in Taiwan 200¥ 20%"""

             

             def groups = {

                def matcher = (it =~ /(.*?)(?: .+)+ (.*)¥ (.*)%/);

               if (matcher.matches())

               {

                  println matcher[0]  

               }

             }

             

             goods.split('/n').each(groups)

   

 

运行结果为:

["computer Intel CUP 3000¥ 10%", "computer", "3000", "10"]

["mouse made in China mainland 50¥ 0%", "mouse", "50", "0"]

["memory made in Taiwan 200¥ 20%", "memory", "200", "20"]

 

 

在上面的代码中,正则表达式中的"(?: .+)+"就是"非匹配组"。值得注意的是,该正则表达式的开头"(.*?)",就用到了"最小匹配"的概念,如果我们把其中的问号去掉,变成"最大匹配",那么结果又将是什么样子呢?

 

      def goods =

"""computer Intel CUP 3000¥ 10%

mouse made in China mainland 50¥ 0%

memory made in Taiwan 200¥ 20%"""

             

             def groups = {

                def matcher = (it =~ /(.*)(?: .+)+ (.*)¥ (.*)%/);

               if (matcher.matches())

               {

                  println matcher[0]  

               }

             }

             

             goods.split('/n').each(groups)

   

 

运行结果为:

["computer Intel CUP 3000¥ 10%", "computer Intel", "3000", "10"]

["mouse made in China mainland 50¥ 0%", "mouse made in China", "50", "0"]

["memory made in Taiwan 200¥ 20%", "memory made in", "200", "20"]

 

可以看到,上面就不是我们想要的结果了。