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

Chr*_*oms 9 regex perl6

从下面的例子中,我看到/ /并且m/ /不完全是同义词,与我的预期相反.我认为唯一的理由使用m/ /,而不是/ /是,它允许使用不同的分隔符(如m{ }).为什么他们不同,为什么我要使用一个与另一个?

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

> my @csv_files = dir( test => / csv $ /  );
["SampleSheet.csv".IO]
Run Code Online (Sandbox Code Playgroud)

但最近出现了一个文件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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

无论如何,/ /并且m/ /显然表现不同,我还不清楚为什么.

sml*_*mls 9

/.../和之间的区别m/.../

来自Regexes#词汇约定:

m/abc/;         # a regex that is immediately matched against $_ 
rx/abc/;        # a Regex object 
/abc/;          # a Regex object
Run Code Online (Sandbox Code Playgroud)

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

  • /.../并将rx/.../指定的正则表达式作为Regex对象返回,而不是将其与任何内容相匹配.
  • m/.../立即对匹配一个储存在变量中的字符串指定的正则表达式$_(即所谓的"主题"),并返回结果作为Match对象,或者Nil如果没有匹配.

示范:

$_ = "Foo 123";

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

say /\d+/;         # /\d+/
say /\d+/.^name;   # Regex
Run Code Online (Sandbox Code Playgroud)

有关您的代码的说明和评论

应用正则表达式修饰符

但最近以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
Run Code Online (Sandbox Code Playgroud)

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

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

my @csv_files = dir( test => rx:i/ csv $ / );
Run Code Online (Sandbox Code Playgroud)
my @csv_files = dir( test => / :i csv $ / );
Run Code Online (Sandbox Code Playgroud)

阻止作为智能匹配器

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

> my @csv_files = dir( test => { m:i/ csv $ / } );
Run Code Online (Sandbox Code Playgroud)

这也有效.这里发生的是:

  • { ... }创建一个采用单个参数的块(可$_在块内部使用).
  • m:i/ ... /系统中的块对匹配$_,并返回Match.
  • 因为它m:i/.../是块中的最后一个语句,所以它Match成为块的返回值.
  • 函数的test副词dir接受任何智能匹配器,它不仅包括Regex对象,还包括Block对象(请参阅智能匹配运算符~~的文档).

使用a Regex作为Bool

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

> my @csv_files = dir( test => { / csv $ / } );
[]
Run Code Online (Sandbox Code Playgroud)

当一个块被用作智能匹配器时,它首先被调用,然后它的返回值被强制转换为Bool:True表示它匹配,False意味着它没有.

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

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

say /\d+/.Bool;  # False

$_ = "123";
say /\d+/.Bool;  # True
Run Code Online (Sandbox Code Playgroud)

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

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

$_ = "abc 123";
.say for dir test => { / \d+ / }  # Returns all filenames
Run Code Online (Sandbox Code Playgroud)

按扩展名过滤文件

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

> my @csv_files = dir( test => / csv $ /  );
Run Code Online (Sandbox Code Playgroud)

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

my @csv-files = dir test => / ".csv" $ /;
Run Code Online (Sandbox Code Playgroud)
my @csv-files = dir.grep: *.extension eq "csv"
Run Code Online (Sandbox Code Playgroud)

或不区分大小写的版本:

my @csv-files = dir test => / :i ".csv" $ /;
Run Code Online (Sandbox Code Playgroud)
my @csv-files = dir.grep: *.extension.lc eq "csv"
Run Code Online (Sandbox Code Playgroud)

  • 感谢您前进第二英里,并提供全面的"关于您的代码的解释和评论"部分! (3认同)