我试图了解{1.9}环境中.{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 。你帮我理解了整个概念!
答案 0 :(得分:3)
{n}
表示“重复前一个原子n
次”。在正则表达式中,原子是一个独立的单元。所以单个字符就是一个原子。这是一个点。一个组也是一个原子(包含其他原子),也就是一个字符类。因此.{n}
表示“匹配n
字符”(因为.
表示“匹配任何字符”)。
请注意,{n}
不像是反向引用,因为它不必在每次重复时匹配相同的文本。 .{5}
的行为与.....
完全相同。
这种结构也更强大。它可以采用两个数字,并且它匹配整个范围的重复计数。所以.{3,5}
表示“匹配3到5个字符”。 .{3,}
表示“匹配3个或更多字符”。如果您愿意,?
可以替换为{0,1}
,*
替换为{0,}
,+
替换为{1,}
。
?<option:
实际上不是一件事。它是(?<option>:<pattern>)
,这会在<option>
期间打开<pattern>
中列出的所有标记。它就像一个组,除了它实际上没有创建一个后引用。因此,表达式(?m:.)
表示“匹配一个字符,好像标记m
已打开”。鉴于m
的行为与nhahtdh在评论中所说的“匹配\ 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,后跟任意两个字符(但换行符),后跟任何字符,并锚定到字符串的末尾或刚好在换行符之前”。
因此,在3场比赛的每场比赛中,fin
都与f.{2}
相匹配。 (?m:.)
匹配第一个\n
,第二个\r
和第三个d
。并且\Z
匹配第一个字符串的结尾,就在第二个字符串中的换行符之前,以及第三个字符串中字符串的结尾。
fi\n\n
不匹配,因为\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/
=> []
我认为你有副本&amp;在这里粘贴错误。这与之前的模式和匹配相同。
> %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:.)
的含义。这不再改变选项。现在它只是一个匹配模式m:.
的捕获组,当然这不会出现在您的输入中。
> %W{fin\n fi\n\n \n\n fin\r\n find}.grep /f.(?m:.)\z/
=> []
您在此处将\Z
更改为\z
。这两者之间的差异\Z
可能在尾随换行符之前匹配,但\z
必须仅匹配字符串的结尾。如果无法在尾随换行符之前匹配,则此处的输入都不匹配。但是,例如,如果您有fin
(没有新行)或fi\n
(没有第二个换行符),那么它就会有用。