/.../
和m/.../
的区别
来自正则表达式#词法约定:
m/abc/; # a regex that is immediately matched against $_
rx/abc/; # a Regex object
/abc/; # a Regex object
换句话说,
/.../
和
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
你的代码的解释和评论
应用正则表达式修饰符
but recently a file ending in Csv showed up. So I tried matching case insensitively
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 $ / );
块作为智能匹配器
I found that I could fix this by putting a block around the matching expression:
> my @csv_files = dir( test => { m:i/ csv $ / } );
这也是可行的。具体实现如下:
{ ... }
创建一个块,该块接受一个参数(可以在块内部使用 $_
)。
- 在块内使用的
m:i/ ... /
标识符对 $_
进行匹配,并返回一个 Match
对象。
- 因为
m:i/.../
是块中的最后一个语句,所以其 Match
对象成为该块的返回值。
dir
函数的 test
副词接受任何智能匹配器,其中包括不仅限于 Regex
对象而且还包括 Block
对象(请参阅 智能匹配运算符 ~~
的文档)。
将Regex
用作Bool
类型
However, if I had used a block around the original expression it doesn't match with the bare / /, but it does with m/ /:
> my @csv_files = dir( test => { / csv $ / } );
[]
当块被用作智能匹配器时,它首先被调用,然后将其返回值强制转换为
Bool
:
True
表示匹配成功,
False
表示未匹配成功。
在此情况下,您的块始终返回一个
Regex
对象。
将正则表达式对象强制转换为布尔值,立即将其与当前的
$_
进行匹配,并且如果正则表达式匹配,则返回
True
,否则返回
False
。
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
通过文件扩展名过滤文件
I am searching for CSV files in a directory. At first I searched for files ending in csv, thus (all code shown as seen from the Perl 6 REPL):
> my @csv_files = dir( test => / csv $ / );
这不仅会找到扩展名为 CSV 的文件,还会找到以三个字母 cvs
结尾的所有文件,包括像 foobarcsv
或 foobar.xcsv
这样的文件。
以下是只查找 CSV 文件的两种更好的写法:
my @csv-files = dir test => / ".csv" $ /;
my @csv-files = dir.grep: *.extension eq "csv"
或者不区分大小写的版本:
my @csv-files = dir test => / :i ".csv" $ /;
my @csv-files = dir.grep: *.extension.lc eq "csv"