Why aren't // and t // exactly synonymous?

From the examples below, I see that / / and m/ / not completely synonymous, contrary to expectations. I thought that the only reason for using m/ / instead of / / was that it allows you to use different delimiters (for example, m{ } ). Why are they different and why do I want to use them compared to others?

I am looking for CSV files in a directory. At first I searched for files ending in csv this way (all the code is shown as seen from the Perl 6 REPL):

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

but recently a file ending in csv . Therefore, I tried to be case insensitive:

 > 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 can fix this by putting a block around the corresponding expression:

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

However, if I used a block around the original expression, it would not match the bare / / but 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 a case-friendly adverb inside / / , it really works:

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

In any case, / / and m/ / obviously behave differently, and it is not clear to me why.

+8
regex perl6
source share
1 answer

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

From Rexes # Lexical conventions :

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

In other words, these are /.../ and rx/.../ , which are synonyms, and not /.../ and m/.../ :

  • /.../ and rx/.../ return the specified regular expression as a Regex object, without matching it with anything at the moment.
  • m/.../ immediately matches the specified regular expression with the string stored in the variable $_ (the so-called "theme"), and returns the result as Match 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 and comments regarding your code

Using regex modifiers

but recently a file ending in Csv has appeared. Therefore, I tried not to be case sensitive.

  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 

This code immediately matches the regular expression regarding the topic $_ calling area that is not initialized. This includes converting it to a string (which triggers the Use of uninitialized value of type Any in string context warning) and returns Nil because there is no match. So you essentially call the dir( test => Nil ) function dir( test => Nil ) .

To make it work, use rx or use the adverb :i inside the regular expression:

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

Blocks like smart sockets

I found that I can fix this by putting a block around the corresponding expression:

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

This also works. What is going on here is:

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

Using Regex as a Bool

However, if I used a block around the original expression, it does not match bare //, but it works with m //:

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

When a block is used as smart matches, it is first called, and then its return value is forced to Bool : True means that it matches, and False means that it is not.

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

Forcing a regular expression object to a logical one immediately matches it with the current $_ and returns True if the corresponding regular expression, and `False if it is not:

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

So, in your code, the regular expression is checked again on $_ , and not on file names:

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

Filter files by their extension

I am looking for CSV files in a directory. At first I searched for files ending in csv this way (all code is shown in Perl 6 REPL):

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

This is not just a search for files with the CSV extension, but all files that end with three letters cvs , including those that look like foobarcsv or foobar.xcsv .
Here are two best ways to record if you only need CSV files:

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

Or case-insensitive version:

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

All Articles