Perl extract matches from list
I'm fairly new to perl but not to scripting languages. I have a file, and I'm trying to extract just one portion of each line that matches a regex. For example, given the file:
FLAG(123)
FLAG(456)
Not a flag
FLAG(789)
I'd like to extract the list [123, 456, 789]
The regex is obviously /^FLAG\((\w+)/
. My questi开发者_如何学运维on is, what's an easy way to extract this data in perl?
It's obviously not hard to set up a loop and do a bunch of =~
matches, but I've heard quite a bit about perl's terseness and how it has an operator for everything, so I'm wondering if there's a slick, simple way to do this.
Also, can you point me towards a good perl reference where I can find out slick ways to do other things like this when the opportunity next arises? There are many perl resources on the web, but 90% of them are too simple and the other 10% I seem to lose the signal in the noise.
Thanks!
Here's how I would do it... Did you learn anything new and/or helpful?
my $file_name = "somefile.txt";
open my $fh, '<', $file_name or die "Could not open file $file_name: $!";
my @list;
while (<$fh>)
{
push @list, $1 if /^FLAG\((\w+)/;
}
Things worth pointing out:
- In a
while
loop condition (and ONLY in a while loop condition), reading from a filehandle will set the value to$_
and check that the file was read automatically. - A statement can be modified by attaching an
if
,unless
,for
,foreach
,while
, oruntil
to the end of it. Then it works as a conditional or loop on that one statement. - You probably know that regex capture groups are stored in
$1
,$2
, etc., but you might not have known that the statement will work even if the statement has anif
suffix. Theif
is evaluated first, sopush @list, $1 if /some_regex/
makes sense and will do the match first, assigning to$1
before it is needed in thepush
statement.
Assuming that you have all of the data together in a single string:
my @matches = $data =~ /^FLAG\((\w+)/mg;
The /g
modifier means to match as many times as possible, the /m
makes ^
match after any newline (not only at the beginning of the string) and a match in list context returns all of the captures for all of those matches.
If you're reading the data in line-by-line then Platinum Azure's solution is the one you want.
map
is your friend here.
use strict;
use warnings;
use File::Slurp;
my @matches = map { /^FLAG\((\w+)/ } read_file('file.txt');
精彩评论