为什么//和 m//不是完全同义的? [英] Why aren't // and m// exactly synonymous?

查看:49
本文介绍了为什么//和 m//不是完全同义的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

<代码>>我的@csv_files = dir( test =>/csv $/);[SampleSheet.csv".IO]

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

<代码>>我的@csv_files = dir( test => m:i/csv $/);在字符串上下文中使用 Any 类型的未初始化值.方法 .^name、.perl、.gist 或 .say 可用于将其字符串化为有意义的内容.在块<单元>中在<未知文件>1号线

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

<代码>>我的@csv_files = dir( test => { m:i/csv $/} );[SampleSheet.csv".IO]

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

<代码>>我的@csv_files = dir( test => {/csv $/} );[]>我的@csv_files = dir( test => { m/csv $/} );[SampleSheet.csv".IO]

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

<代码>>我的@csv_files = dir( test =>/:i csv $/);[SampleSheet.csv".IO]

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

解决方案

/.../m/.../ 的区别

来自 Regexes#Lexical 约定:

<块引用>

m/abc/;# 一个与 $_ 立即匹配的正则表达式接收/ABC/;# 一个正则表达式对象/ABC/;# 一个正则表达式对象

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

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

演示:

$_ = "Foo 123";说 m/\d+/;#「★123」说 m/\d+/.^name;# 比赛说/\d+/;#/\d+/说/\d+/.^name;# 正则表达式

<小时>

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

应用正则表达式修饰符

<块引用>

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

 my @csv_files = dir( test => m:i/csv $/);在字符串上下文中使用 Any 类型的未初始化值.方法 .^name、.perl、.gist 或 .say 可用于将其字符串化为有意义的内容.在块<单元>中在<未知文件>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 $/);

<小时>

块作为智能匹配器

<块引用>

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

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

这也行.这里发生的是:

  • { ... } 创建一个接受单个参数的块(在块内以 $_ 形式提供).
  • 块内的 m:i/.../$_ 匹配,并返回一个 Match.
  • 因为 m:i/.../ 是块中的最后一条语句,它的 Match 成为块的返回值.
  • dir 函数的 test 副词接受任何智能匹配器,其中不仅包括 Regex 对象,还包括 Block 对象(请参阅 智能匹配运算符 ~~).
<小时>

使用 Regex 作为 Bool

<块引用>

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

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

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

在这种情况下,您的块总是返回一个 Regex 对象.

将正则表达式对象强制为布尔值,立即将其与当前的 $_ 进行匹配,如果正则表达式匹配则返回 True,如果不匹配则返回 `False:

say/\d+/.Bool;# 错误的$_ = "123";说/\d+/.Bool;# 真的

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

$_ = "abc";.say for dir test =>{/\d+/} # 不返回文件名$_ = "abc 123";.say for dir test =>{/\d+/} # 返回所有文件名

<小时>

按扩展名过滤文件

<块引用>

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

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

这不仅会查找具有 CSV 扩展名的文件,还会查找以三个字母 cvs 结尾的所有文件,包括像 foobarcsvfoobar.xcsv.
如果您只需要 CSV 文件,这里有两种更好的编写方法:

我的@csv-files = dir test =>/".csv" $/;

我的@csv-files = dir.grep: *.extension eq "csv"

或者不区分大小写的版本:

我的@csv-files = dir test =>/:i ".csv" $/;

我的@csv-files = dir.grep: *.extension.lc eq "csv"

From the examples below, I see that / / and m/ / aren't exactly synonymous, contrary to what I expected. I thought that the only reason to use m/ / instead of / / was that it allows using different delimiters (e.g. m{ }). Why are they different and why would I want to use one versus the other?

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 $ /  );
["SampleSheet.csv".IO]

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

I found that I could fix this by putting a block around the matching expression:

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

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 $ / } );
[]
> my @csv_files = dir( test => { m/ csv $ / } );
["SampleSheet.csv".IO]

Then I found out that if I used the case-insensitive adverb inside / /, it does work:

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

Anyway, / / and m/ / are clearly behaving differently and it's not yet clear to me why.

解决方案

The difference between /.../ and m/.../

From Regexes#Lexical conventions:

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

In other words, it's /.../ and rx/.../ that are synonyms, not /.../ and m/.../:

  • /.../ and rx/.../ return the specified regex as a Regex object, without matching it against anything for now.
  • m/.../ immediately matches the specified regex against the string that's stored in the variable$_ (the so-called "topic"), and returns the result as a Match object, or as Nil if there was no match.

Demonstration:

$_ = "Foo 123";

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

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


Explanations & comments regarding your code

Applying regex modifiers

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

That code immediately matches the regex against the topic $_ of the calling scope, which is uninitialized. This involves converting it to a string (which causes the warning Use of uninitialized value of type Any in string context), and returns Nil because there is no match. So you're essentially calling the function as dir( test => Nil ).

To make it work, either use rx or apply the :i adverb inside the regex:

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

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


Blocks as smart-matchers

I found that I could fix this by putting a block around the matching expression:

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

That works too. What happens here, is:

  • { ... } creates a block that takes a single argument (which is available as $_ inside the block).
  • The m:i/ ... / inside the block matches against $_, and returns a Match.
  • Because the m:i/.../ is the last statement in the block, its Match becomes the return value of the block.
  • The test adverb of the dir function accepts any smart-matcher, which includes not just Regex objects but also Block objects (see the documentation for the smart-match operator ~~).

Using a Regex as a 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 $ / } );
[]

When a block is used as a smart-matcher, it is first called and then its return value is coerced to a Bool: True means it matched, and False means it didn't.

In this case, your block always returs a Regex object.

Coercing a regex object to a boolean, immediately matches it against the current $_, and returns True if the regex matched, and `False if it didn't:

say /\d+/.Bool;  # False

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

So in your code, the regex ends up being repeatedly checked against $_, rather than against the filenames:

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

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


Filtering files by their extension

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 $ /  );

This doesn't just find files that have the CSV extension, but all files that end in the three letters cvs, including ones like foobarcsv or foobar.xcsv.
Here are two better ways to write it if you only want CSV files:

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

my @csv-files = dir.grep: *.extension eq "csv"

Or the case-insensitive version:

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

my @csv-files = dir.grep: *.extension.lc eq "csv"

这篇关于为什么//和 m//不是完全同义的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆