从下面的示例中,我发现/ /
和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/ /
的行为明显不同,我现在还不清楚原因。
答案 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
但最近以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 $ / } ); []
当一个块用作智能匹配器时,首先调用它,然后将其返回值强制转换为Bool
:True
表示匹配,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" $ /;