<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>__main__ (星期六的黄昏)</title>
    <link>https://ruby-china.org/__main__</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>省略括号导致的语法歧义</title>
      <description>&lt;p&gt;  今天早上原本想整理一篇利用 regexp 对象的 to_s 方法实现正则表达式嵌套的文章，但在整理代码的过程中确偶然出现了一个小插曲：使用 puts 语句输出一个正则总会报语法错误。出错的代码如下：
&lt;code&gt;puts / s /xi&lt;/code&gt;
这时会报一个语法错误：  &lt;strong&gt;syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '(' .&lt;/strong&gt;  这个表达式是完全正确的一个正则表达式，这时你如果这样把 puts 省略的括号添加上就没有问题了，说明表达式就没有问题的。更有意思的在后面，如果我们在代的前面添加两行代码，变成下面这样：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="sr"&gt;/xi
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还是报错，不过错误提示换了：&lt;strong&gt;undefined method '/' for nil:NilClass (NoMethodError)&lt;/strong&gt; 有意思吧。如果一件事情的结果总是摇摆不定，很有可能就是我们没有搞清楚事情背后的真正原因。就这件事情来说，造成这种现象的根本原因应该是最初的那行代码因为省略的括号导致了语法歧义。&lt;/p&gt;

&lt;p&gt;  在原生支持正则的语言中除号有两个作用：1. 作为除法运算的符号 2. 作为正则表达式的开始。那么对于那行代码的理解也就有了两种可能：1. 作为除号去理解所以那行代码会等价于：
&lt;code&gt;(foo) / (s) / (xi)&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;作为正则表达式去理解，所以代码等价于
&lt;code&gt;foo (/ s  /xi)&lt;/code&gt;
一开始的时候解释器按正则来理解的，但比较诡异的是他报了正则错误，这有点让人搞不懂，明明已经知道是正则了，不知道正则有 x 模式吗？感觉这似乎是词法程序的一个 bug。第二次解释器可能根据上下文做了判断认为是除法的可能性更大一些，所以按除法去理解的，但因为 puts 返回的结果是 nil 所以报了哪个错误。如果我们把括号补全那么这种歧义也就消失了，就都会按正则来理解。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;  感觉 ruby 的这种处理方式是有一些危险性的。如果在真实的项目中真的出现了这种歧义的代码而 Ruby 不报错而是做猜测，并且恰好猜对了，之后有人添加了两行代码，并且恰好改变了当时的语义环境使解释器做了另一个决策，那就会出问题了。&lt;/p&gt;

&lt;p&gt;  在 JS 中因为不能省略括号，所以这种歧义代码是不可能出现的，因为 JS 的判断策略是固定的，只要除号的前面是 name 也就是我们定义的变量或对象属性，那就一定是除号否则就是正则。但 Ruby 中因为可以省略括号所以造成了这种二义性代码的存在。 &lt;strong&gt;因此建议大家写代码的时候最好给方法调用带上括号，避免这种二义性代码的产生，省略是有代价的。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  以上代码的测试环境： &lt;strong&gt;win7, ruby 2.0.0p247&lt;/strong&gt;。自己是业余 ruby 玩家，文中如果错误，欢迎大家指正&lt;/p&gt;</description>
      <author>__main__</author>
      <pubDate>Tue, 17 Sep 2013 09:33:21 +0800</pubDate>
      <link>https://ruby-china.org/topics/14173</link>
      <guid>https://ruby-china.org/topics/14173</guid>
    </item>
    <item>
      <title>利用 to_s 实现正则嵌套</title>
      <description>&lt;h2 id="事情的起因"&gt;事情的起因&lt;/h2&gt;
&lt;p&gt;  最近接到了一个很有意思的任务：统计下我们团队的 JS 代码中各种 CSS 选择器的使用频率。接到任务之后还是很兴奋的。平时就很喜欢折腾正则，最近项目比较忙，调试 IE 的各种样式 Bug 调的昏天黑地的，有机会换换口味，写点自己喜欢的代码，也算是很好的消遣了。但真的写起来之后却碰到了一点小麻烦。&lt;/p&gt;

&lt;p&gt;  首先，这个问题的解决不能简单粗暴的采用正则表达式抓取代码中 &lt;strong&gt;长得像&lt;/strong&gt; CSS 表达式的文本的方式来解决。因为 JS 代码中长得像 CSS 表达式的实在太多了，比如： &lt;strong&gt;c = a + b&lt;/strong&gt;  ， &lt;strong&gt;a + b&lt;/strong&gt;  是一个标准的兄弟选择器； &lt;strong&gt;if(a&amp;gt;b)&lt;/strong&gt;  ， &lt;strong&gt;a &amp;gt; b&lt;/strong&gt; 是合法的子代选择；而 &lt;strong&gt;var a, b, c, d&lt;/strong&gt; 这种情况就更常见了，同样的 &lt;strong&gt;a,b, c, d&lt;/strong&gt; 也是合法的选择器。所以如果粗暴的用正则去抓取像选择器的文本是没有意义的，得到的数据质量太低。因此我换了一种思路来处理：找到支持选择器的函数，然后用正则抓取对应的参数。这样精度就高了许多。比如如果我们要统计使用 jQuery 的 JS 代码中的 CSS 选择器的使用频率，那么我们只需要统计 jQuery 中支持选择器的几个函数就可以了，比如我们可以统计符合这几种格式的字符串： &lt;strong&gt;$('selector')&lt;/strong&gt; ，  &lt;strong&gt;.find('selector')&lt;/strong&gt;， &lt;strong&gt;.parents('selector')&lt;/strong&gt;等等&lt;/p&gt;
&lt;h2 id="遇到的问题"&gt;遇到的问题&lt;/h2&gt;
&lt;p&gt;  方法找到了就可以动手做了。不过刚动手就遇到了一个当初不曾预料到的一个问题： &lt;strong&gt;这个正则太大了，而且有太多重复的内容&lt;/strong&gt; 。我们就以 jQuery 中的$函数来举例说明。jQuery 中$函数的参数格式是：&lt;strong&gt;$(selecotr [, context])&lt;/strong&gt;  ，有 4 种可能的参数组合是我们所需要的：&lt;strong&gt;$('selecotr', 'selector')&lt;/strong&gt; 、 &lt;strong&gt;$('selecotr')&lt;/strong&gt; 、     &lt;strong&gt;$('selector',not_selector)&lt;/strong&gt; 、 &lt;strong&gt;$(not_selector, 'selecotr')&lt;/strong&gt;  。selecotr 的字符串可能是单引号也可能是双引号。因此为了匹配这样一个结构我们需要类似如下的一个表达式：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;reg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;%r{
    [^&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="sr"&gt;$]  # $不能是其他变量的结尾
    &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;* &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;* (?:
        (?: # 匹配格式$('selector' [, 'selector'])
            (?&amp;lt;prop_1&amp;gt;
                  ' (?: [^'&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;' )*? ' 
                | " (?: [^"&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;" )*? "             
            )
            (?:
                (?&amp;lt;comma&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;* , &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*)            
                (?&amp;lt;prop_2&amp;gt;
                      ' (?: [^'&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? ' 
                    | " (?: [^"&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? "                
                )            
            )?
        )

      | (?: # 匹配格式$('selector', not-selecotr)
            (?&amp;lt;prop_1&amp;gt;
                  ' (?: [^'&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? ' 
                | " (?: [^"&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? "                
            )             
            (?&amp;lt;comma&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;* , &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*)
            (?: [&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="sr"&gt;$.]+ )
        )        

      | (?: # 匹配格式$(not-selecotr, 'selector')
            (?: [&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="sr"&gt;$.]+ )
            (?&amp;lt;comma&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;* , &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;* )
            (?&amp;lt;prop_2&amp;gt;
                  ' (?: [^'&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? ' 
                | " (?: [^"&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? "                
            )             
        )
  )  &lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;* &lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="sr"&gt;
}x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为了说明方便 not_selector 部分与项目中使用大代码相比做了适当的简化，不考虑用方括号引用属性比如：object[prop1][prop2].prop3。​
​
​    不知道大家看到这个表达式有何感受，我的一个同事看到之后直接被吓住了。我自己写这个表达式的时候也很费劲，太长了，稍不注意就会造成括号不匹配的错误。而这只匹配了众多函数中的一个，还有好几种可能的结构需要匹配。那么最终的的表达式将比这个还要长，还要恐怖很多。而且可以看到这个表达式中有很多内容是重复出现的，比如匹配字符串、匹配逗号等。因此我需要一种方式将表达式拆分成一些小的单位，然后将他们组合在一起。但正则的语法中没有变量之类的方案帮我们做这些事情，所以需要我们自己去想办法了。&lt;/p&gt;
&lt;h3 id="解决方案"&gt;解决方案&lt;/h3&gt;
&lt;p&gt;  最容易想的方案就是试下能不能使用#{}在正则中引入变量。试了下，比较幸运，是可以的。而且还有一个好消息是 Regexp 对象的 to_s 方法会返回一个转义之后正则表达式字符串，而通过#{}引入的变量会自动调用对象的 to_s 方法，因此我们可以利用这些特性将我们的大的正则表达式拆分成小块然后组合起来。看下我们拆分之后的代码&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_scan_reg&lt;/span&gt;
  &lt;span class="n"&gt;not_selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/[\w$.]+/&lt;/span&gt; 
  &lt;span class="n"&gt;not_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/[^\w$]/&lt;/span&gt;
  &lt;span class="n"&gt;comma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/ \s* , \s* /x&lt;/span&gt;
  &lt;span class="n"&gt;lb&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/ \s* \( \s* /x&lt;/span&gt;
  &lt;span class="n"&gt;rb&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/ \s* \)/x&lt;/span&gt;
  &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;%r{
    (?: 
        ' (?: [^'&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? ' 
      | " (?: [^"&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? "             
    )
  }x&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sr"&gt;%r{
    &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;not_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;lb&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; (?:
        (?:
          (?&amp;lt;prop_1&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;)
          (?: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;comma&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; (?&amp;lt;prop_2&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;) )?            
        )  
      | (?: (?&amp;lt;prop_1&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;) &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;comma&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;not_selector&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; )        
      | (?: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;not_selector&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;comma&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; (?&amp;lt;prop_2&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;) )
    ) &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;
  }x&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;​虽然还是有些复杂，但与原来相比好理解很多了。至此已经满足我的需求了，基本可以打住了，但使用 puts 输出下生成的正则后发现，还是有点瑕疵。每一个变量的外层被包了一个括号变成了一个非捕获分组，这样多少会对性能有所影响，因此我们动手把这个细节修复下。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;def_reg_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;  
  &lt;span class="n"&gt;inst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
  &lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define_singleton_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:to_s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;asGroup&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^\(.*?:|\)$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inst&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; 

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_scan_reg&lt;/span&gt;
  &lt;span class="n"&gt;not_selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;def_reg_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[\w$.]+/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="n"&gt;not_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;def_reg_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[^\w$]/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;comma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;def_reg_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/ \s* , \s* /x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;lb&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;def_reg_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/ \s* \( \s* /x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;rb&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;def_reg_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/ \s* \) /x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;def_reg_part&lt;/span&gt; &lt;span class="sr"&gt;%r{
    (?: 
        ' (?: [^'&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? ' 
      | " (?: [^"&lt;/span&gt;&lt;span class="se"&gt;\n\\&lt;/span&gt;&lt;span class="sr"&gt;] | &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;. )*? "             
    )
  }x&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sr"&gt;%r{
    &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;not_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;lb&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; (?:
        (?:
            (?&amp;lt;prop_1&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;)
            (?: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;comma&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; (?&amp;lt;prop_2&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;) )?            
        )  
      | (?: (?&amp;lt;prop_1&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;) &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;comma&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;not_selector&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; )        
      | (?: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;not_selector&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;comma&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; (?&amp;lt;prop_2&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;) )
    ) &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;
  }x&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就满足我的需求了，这是目前为止我能找到的最好方案了，如果大家有好的方案希望能够指点一二 &lt;/p&gt;</description>
      <author>__main__</author>
      <pubDate>Mon, 16 Sep 2013 17:40:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/14164</link>
      <guid>https://ruby-china.org/topics/14164</guid>
    </item>
  </channel>
</rss>
