为什么不和//和m //完全同义?

时间:2017-07-26 12:28:18

标签: regex perl6

从下面的示例中,我发现/ /m/ /并不完全是同义词,与我的预期相反。我认为使用m/ /代替/ /的唯一原因是它允许使用不同的分隔符(例如m{ })。为什么它们不同,为什么我要使用一个与另一个?

我在目录中搜索CSV文件。起初我搜索了以csv结尾的文件,因此(显示的所有代码都是从Perl 6 REPL中看到的):

> my @csv_files = dir( test => / csv $ /  );
["SampleSheet.csv".IO]

但最近出现了一个以Csv结尾的文件。所以我尝试不区分大小写:

> my @csv_files = dir( test => m:i/ csv $ / );
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
  in block <unit> at <unknown file> line 1

我发现我可以通过在匹配表达式周围放置一个块来解决这个问题:

> my @csv_files = dir( test => { m:i/ csv $ / } );
["SampleSheet.csv".IO]

但是,如果我在原始表达式周围使用了一个块,则它与裸/ /不匹配,但它与m/ /匹配:

> my @csv_files = dir( test => { / csv $ / } );
[]
> my @csv_files = dir( test => { m/ csv $ / } );
["SampleSheet.csv".IO]

然后我发现如果我在/ /中使用不区分大小写的副词,它确实有效:

> my @csv_files = dir( test => /:i csv $ / );
["SampleSheet.csv".IO]

无论如何,/ /m/ /的行为明显不同,我现在还不清楚原因。

1 个答案:

答案 0 :(得分:9)

/.../m/.../

之间的差异

来自Regexes#Lexical conventions

m/abc/;         # a regex that is immediately matched against $_ 
rx/abc/;        # a Regex object 
/abc/;          # a Regex object

换句话说,/.../rx/.../是同义词,而不是/.../m/.../

  • /.../rx/.../将指定的正则表达式作为Regex对象返回,暂时不将其与任何内容进行匹配。
  • m/.../立即将指定的正则表达式与存储在变量$_中的字符串(所谓的&#34; topic&#34;)匹配,并将结果返回为Match对象,如果没有匹配,则为Nil

演示:

$_ = "Foo 123";

say m/\d+/;        # 「123」
say m/\d+/.^name;  # Match

say /\d+/;         # /\d+/
say /\d+/.^name;   # Regex

解释&amp;关于您的代码的评论

应用正则表达式修饰符

  

但最近以Csv结尾的文件出现了。所以我尝试不区分大小写

 my @csv_files = dir( test => m:i/ csv $ / );
 Use of uninitialized value of type Any in string context.
 Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
   in block <unit> at <unknown file> line 1

该代码立即将正则表达式与调用范围的主题$_进行匹配,该主题未初始化。这涉及将其转换为字符串(导致警告Use of uninitialized value of type Any in string context),并返回Nil因为没有匹配。因此,您实际上将该函数称为dir( test => Nil )

要使其有效,请使用rx或在正则表达式中应用:i副词:

my @csv_files = dir( test => rx:i/ csv $ / );
my @csv_files = dir( test => / :i csv $ / );

阻止作为智能匹配器

  

我发现我可以通过在匹配表达式周围放置一个块来解决这个问题:

> my @csv_files = dir( test => { m:i/ csv $ / } );

也有效。这里发生的是:

  • { ... }创建一个带有单个参数的块(在块内可用$_)。
  • 块内的m:i/ ... /$_匹配,并返回Match
  • 由于m:i/.../是块中的最后一个语句,因此Match成为块的返回值。
  • test函数的dir副词接受任何智能匹配器,其中不仅包括Regex个对象,还包括Block个对象(请参阅{{的文档) 3}})。

使用Regex作为Bool

  

但是,如果我在原始表达式周围使用了一个块,它与裸/ /不匹配,但它与m / /相符:

> my @csv_files = dir( test => { / csv $ / } );
[]

当一个块用作智能匹配器时,首先调用它,然后将其返回值强制转换为BoolTrue表示匹配,False表示它没&#39;吨

在这种情况下,您的块始终会返回Regex个对象。

将正则表达式对象强制转换为布尔值,立即将其与当前$_匹配,如果正则表达式匹配则返回True,如果不匹配,则返回“假”:

say /\d+/.Bool;  # False

$_ = "123";
say /\d+/.Bool;  # True

因此,在您的代码中,正则表达式最终会针对$_重复检查,而不是针对文件名:

$_ = "abc";
.say for dir test => { / \d+ / }  # Returns no filenames

$_ = "abc 123";
.say for dir test => { / \d+ / }  # Returns all filenames

按扩展名过滤文件

  

我在目录中搜索CSV文件。起初我搜索了以csv结尾的文件,因此(所有代码显示为从Perl 6 REPL中看到的):

> my @csv_files = dir( test => / csv $ /  );

这不仅仅是查找具有CSV扩展名的文件,而是以三个字母cvs结尾的所有文件,包括foobarcsv或{ {1}}。
如果您只想要CSV文件,可以使用以下两种方法编写它:

foobar.xcsv
my @csv-files = dir test => / ".csv" $ /;

或不区分大小写的版本:

my @csv-files = dir.grep: *.extension eq "csv"
my @csv-files = dir test => / :i ".csv" $ /;