2

我试图了解如何在Ruby 1.9.3 环境中.{n} 工作。但无法理解以下代码如何产生输出:?<option>:Regexp

irb(main):001:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{2}(?m:.)\Z/
=> ["fin\n", "fin\r\n", "find"]
irb(main):002:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{1}(?m:.)\Z/
=> ["fin\n", "fi\n\n"]
irb(main):003:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{1}(?m:.)\Z/
=> []
irb(main):010:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\Z/
=> ["fin\n", "fi\n\n"]
irb(main):011:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(m:.)\Z/
=> []
irb(main):012:0> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\z/
=> []

谁能帮我理解上面的代码是如何在IRB终端中生成上述输出的?

谢谢,


根据@Kevin最后一段,我在下面尝试并找到了预期和理想的输出:

irb(main):014:0> %W{fin fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\z/
=> ["fin"]
irb(main):015:0> %W{fin fi\n\n \n\n fin\r find}.grep /f.(?m:.)\z/
=> ["fin"]
irb(main):016:0> %W{fin fi\n \n\n fin\r\n find}.grep /f.(?m:.)\z/
=> ["fin", "fi\n"]
irb(main):017:0> %W{fin fi\n \n\n fr\n find}.grep /f.(?m:.)\z/
=> ["fin", "fi\n", "fr\n"]
irb(main):018:0>

非常感谢@Kevin。你帮助我理解了整个概念!

4

1 回答 1

3

{n}意思是“重复以前的原子n时间”。在正则表达式中,原子是一个自包含的单元。所以单个字符是一个原子。一个点也是如此。一个组也是一个原子(包含其他原子),字符类也是如此。所以.{n}意味着“匹配n字符”(因为.意味着“匹配任何字符”)。

请注意,这{n}不像反向引用,因为它不必在每次重复时都匹配相同的文本。.{5}行为与......

这个结构也更强大。它可以采用两个数字,并且匹配整个范围的重复计数。所以.{3,5}意味着“匹配 3 到 5 个字符”。并.{3,}表示“匹配 3 个或更多字符”。如果您愿意,?可以用{0,1}、和替换。*{0,}+{1,}


?<option:实际上不是一回事。它是(?<option>:<pattern>),这会在<option>的持续时间内打开所有列出的标志<pattern>。它就像一个组,只是它实际上并没有创建反向引用。所以表达式的(?m:.)意思是“匹配一个字符,就像m打开了标志一样”。鉴于mnhahtdh 在评论中所说的“匹配 \n”的行为,该表达式的.(?m:.).意思是“匹配除换行符之外的任何字符,后跟任何字符,后跟除换行符之外的任何字符”。

这种结构有两个好处。首先,它允许您仅将标志应用于模式的一部分,这有时会很有用。其次,如果您将整个模式包装在此构造中,那么您可以控制应用于您的正则表达式的标志,而不管该表达式在哪里使用。当您以用户身份提供正则表达式并且无法控制程序的源时,这很有用。


让我们看一下您提供的示例:

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{2}(?m:.)\Z/
=> ["fin\n", "fin\r\n", "find"]

您的模式/f.{2}(?m:.)\Z/意味着“匹配 f,后跟 2 个任何字符(但换行符),后跟任何字符,并锚定到字符串的末尾或换行符之前”。

因此,在 3 场比赛中fin的每场比赛中,都匹配f.{2}. 在第一个、第二个和第三个中(?m:.)匹配。并匹配第一个字符串的结尾,第二个换行符之前,第三个字符串的结尾。\n\rd\Z

fi\n\n不匹配,因为没有标志的from\n无法匹配此处的第一个。..{2}m

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{1}(?m:.)\Z/
=> ["fin\n", "fi\n\n"]

在这两种情况下都fi匹配f.{1}(?m:.)在这两种情况下都匹配n\n,并且\Z在换行符之前匹配。

fin\r\n不匹配,因为\Z只会在字符串中的最后一个换行符之前匹配,而不是在 CRLF 对之前匹配。并且find不匹配,因为没有什么可以匹配d.

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.{1}(?m:.)\Z/
=> []

我认为您在这里有复制和粘贴错误。这与之前的模式相同,并且匹配。

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\Z/
=> ["fin\n", "fi\n\n"]

这也与之前的模式相同。.并且.{1}是一回事。事实上,{1}总是可以从任何正则表达式中剥离而不改变任何东西。

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(m:.)\Z/
=> []

您在此模式中删除了?,更改了 的含义(m:.)。这不再改变选项。现在它只是一个与 pattern 匹配的捕获组m:.,这当然不会出现在您的输入中。

> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\z/
=> []

你换\Z\z了这里。这两者之间的区别\Z可能在尾随换行符之前匹配,但\z必须只匹配字符串的结尾。由于无法在尾随换行符之前进行匹配,因此您在此处的输入均不匹配。但是,例如,如果您有fin(没有换行符)或fi\n(没有第二个换行符)它会起作用。

于 2013-01-17T18:40:07.203 回答