Noob question here. I have a very simple perl script and I want the regex to match multiple parts in the string
my $string = "ohai there. ohai";
my #results = $string =~ /(\w\w\w\w)/;
foreach my $x (#results){
print "$x\n";
}
This isn't working the way i want as it only returns ohai. I would like it to match and print out ohai ther ohai
How would i go about doing this.
Thanks
Would this do what you want?
my $string = "ohai there. ohai";
while ($string =~ m/(\w\w\w\w)/g) {
print "$1\n";
}
It returns
ohai
ther
ohai
From perlretut:
The modifier "//g" stands for global matching and allows the
matching operator to match within a
string as many times as possible.
Also, if you want to put the matches in an array instead you can do:
my $string = "ohai there. ohai";
my #matches = ($string =~ m/(\w\w\w\w)/g);
foreach my $x (#matches) {
print "$x\n";
}
Or you could do this
my $string = "ohai there. ohai";
my #matches = split(/\s/, $string);
foreach my $x (#matches) {
print "$x\n";
}
The split function in this case splits on spaces and prints
ohai
there.
ohai
Related
I realize it is possible to achieve this with a slight workaround, but I am hoping there is a simpler way (since I often make use of this type of expression).
Given the example string:
my $str = "An example: sentence!*"
A regex can be used to match each punctuation mark and capture them in an array.
Thereafter, I can simply repeat the regex and replace the matches as in the following code:
push (#matches, $1), while ($str =~ /([\*\!:;])/);
$str =~ s/([\*\!:;])//g;
Would it be possible to combine this into a single step in Perl where substitution occurs globally while also keeping tabs on the replaced matches?
You can embed code to run in your regular expression:
my #matches;
my $str = 'An example: sentence!*';
$str =~ s/([\*\!:;])(?{push #matches, $1})//g;
But with a match this simple, I'd just do the captures and substitution separately.
Yes, it's possible.
my #matches;
$str =~ s/[*!:;]/ push #matches, $&; "" /eg;
However, I'm not convinced that the above is faster or clearer than the following:
my #matches = $str =~ /[*!:;]/g;
$str =~ tr/*!:;//d;
Use:
my $str = "An example: sentence!*";
my #matches = $str =~ /([\*\!:;])/g;
say Dumper \#matches;
$str =~ tr/*!:;//d;
Output:
$VAR1 = [
':',
'!',
'*'
];
Is that what you're looking for ?
my ($str, #matches) = ("An example: sentence!*");
#first method :
($str =~ s/([\*\!:;])//g) && push(#matches, $1);
#second method :
push(#matches, $1) while ($str =~ s/([\*\!:;])//g);
Try:
my $str = "An example: sentence!*";
push(#mys, ($str=~m/([^\w\s])/g));
print join "\n", #mys;
Thanks.
How to user Perl to find and print all strings that match a regexp?
The following only finds the first match.
$text="?Adsfsadfgaasdf.
?Bafadfdsaadsfadsf.
xcxvfdgfdg";
if($text =~ m/\\?([^\.]+\.)/) {
print "$1\n";
}
EDIT1: /g doesn't work
#!/usr/bin/env perl
$text="?Adsfsadfgaasdf.
?Bafadfdsaadsfadsf.
xcxvfdgfdg";
if($text =~ m/\\?([^\.]+\.)/g) {
print "$1\n";
}
$ ./test.pl
?Adsfsadfgaasdf.
The problem is that the /g modifier does not use capture groups for multiple matches. You need to either iterate over the matches in scalar context, or catch the returned list in list context. For example:
use v5.10; # required for say()
$text="?Adsfsadfgaasdf.
?Bafadfdsaadsfadsf.
xcxvfdgfdg";
while ($text =~ /\?([^.]+\.)/g) { # scalar context
say $1;
}
for ($text =~ /\?[^.]+\./g) { # list context
say; # match is held in $_
}
Note in the second case, I skipped the parens, because in list context the whole match is returned if there are no parens. You may add parens to select part of the string.
Your version, using if, uses scalar context, which saves the position of the most recent match, but does not continue. A way to see what happens is:
if($text =~ m/\?([^\.]+\.)/g) {
print "$1\n";
}
say "Rest of string: ", substr $text, pos;
pos gives the position of the most recent match.
In previous answer #TLP correctly wrote that matching should be in list context.
use Data::Dumper;
$text="?Adsfsadfgaasdf.
?Bafadfdsaa.
dsfadsf.
xcxvfdgfdg";
#arr = ($text =~ /\?([^\.]+\.)/g);
print Dumper(#arr);
Expected result:
$VAR1 = 'Adsfsadfgaasdf.';
$VAR2 = 'Bafadfdsaa.';
You seem to be missing the /g flag, which tells perl to repeat the match as many times as possible.
Is there an easy way to add regex modifiers such as 'i' to a quoted regular expression? For example:
$pat = qr/F(o+)B(a+)r/;
$newpat = $pat . 'i'; # This doesn't work
The only way I can think of is to print "$pat\n" and get back (?-xism:F(o+)B(a+)r) and try to remove the 'i' in ?-xism: with a substitution
You cannot put the flag inside the result of qr that you already have, because it’s protected. Instead, use this:
$pat = qr/F(o+)B(a+)r/i;
You can modify an existing regex as if it was a string as long as you recompile it afterwards
my $pat = qr/F(o+)B(a+)r/;
print $pat, "\n";
print 'FOOBAR' =~ $pat ? "match\n" : "mismatch\n";
$pat =~ s/i//;
$pat = qr/(?i)$pat/;
print $pat, "\n";
print 'FOOBAR' =~ $pat ? "match\n" : "mismatch\n";
OUTPUT
(?-xism:F(o+)B(a+)r)
mismatch
(?-xism:(?i)(?-xsm:F(o+)B(a+)r))
match
Looks like the only way is to stringify the RE, replace (-i) with (i-) and re-quote it back:
my $pat = qr/F(o+)B(a+)r/;
my $str = "$pat";
$str =~ s/(?<!\\)(\(\?\w*)-([^i:]*)i([^i:]*):/$1i-$2$3:/g;
$pati = qr/$str/;
UPDATE: perl 5.14 quotes regexps in a different way, so my sample should probably look like
my $pat = qr/F(o+)B(a+)r/;
my $str = "$pat";
$str =~ s/(?<!\\)\(\?\^/(?^i/g;
$pati = qr/$str/;
But I don't have perl 5.14 at hand and can't test it.
UPD2: I also failed to check for escaped opening parenthesis.
I am matching a string of the form A<=>B!C<=>D!E<=>F... and want to do checks on the letters. Basically I want to tell if the letters are in the class according to a hash I have defined. I had the idea of doing the following regex and then looping through the matched strings:
$a =~ /(.)<=>(.)/g;
But I can't figure out to tell how many $1, $2 variables have matched. How do I know how many there are? Also, is there a better way to do this? I am using Perl 5.8.8.
You'll want the 'countof' operator to count the number of matches:
my $count = () = $string =~ /(.)<=>(.)/g;
Replacing the empty list with an array will retain the matches:
my #matches = $string =~ /(.)<=>(.)/g;
Which provides another way to get the $count:
my $count = #matches; # scalar #matches works too
Use a while loop
use warnings;
use strict;
my %letters = map { $_ => 1 } qw(A C F);
my $s = 'A<=>B!C<=>D!E<=>F';
while ($s =~ /(.)<=>(.)/g) {
print "$1\n" if exists $letters{$1};
print "$2\n" if exists $letters{$2};
}
__END__
A
C
F
Create a variable and increment it each time you go through your loop?
I want to be able to do a regex match on a variable and assign the results to the variable itself. What is the best way to do it?
I want to essentially combine lines 2 and 3 in a single line of code:
$variable = "some string";
$variable =~ /(find something).*/;
$variable = $1;
Is there a shorter/simpler way to do this? Am I missing something?
my($variable) = "some string" =~ /(e\s*str)/;
This works because
If the /g option is not used, m// in list context returns a list consisting of the subexpressions matched by the parentheses in the pattern, i.e., ($1, $2, $3 …).
and because my($variable) = ... (note the parentheses around the scalar) supplies list context to the match.
If the pattern fails to match, $variable gets the undefined value.
Why do you want it to be shorter? Does is really matter?
$variable = $1 if $variable =~ /(find something).*/;
If you are worried about the variable name or doing this repeatedly, wrap the thing in a subroutine and forget about it:
some_sub( $variable, qr/pattern/ );
sub some_sub { $_[0] = $1 if eval { $_[0] =~ m/$_[1]/ }; $1 };
However you implement it, the point of the subroutine is to make it reuseable so you give a particular set of lines a short name that stands in their place.
Several other answers mention a destructive substitution:
( my $new = $variable ) =~ s/pattern/replacement/;
I tend to keep the original data around, and Perl v5.14 has an /r flag that leaves the original alone and returns a new string with the replacement (instead of the count of replacements):
my $match = $variable =~ s/pattern/replacement/r;
Well, you could say
my $variable;
($variable) = ($variable = "find something soon") =~ /(find something).*/;
or
(my $variable = "find something soon") =~ s/^.*?(find something).*/$1/;
You can do substitution as:
$a = 'stackoverflow';
$a =~ s/(\w+)overflow/$1/;
$a is now "stack"
From Perl Cookbook 2nd ed
6.1 Copying and Substituting Simultaneously
$dst = $src;
$dst =~ s/this/that/;
becomes
($dst = $src) =~ s/this/that/;
I just assumed everyone did it this way, amazed that no one gave this answer.
Almost ....
You can combine the match and retrieve the matched value with a substitution.
$variable =~ s/.*(find something).*/$1/;
AFAIK, You will always have to copy the value though, unless you do not care to clobber the original.
$variable2 = "stackoverflow";
(my $variable1) = ($variable2 =~ /stack(\w+)/);
$variable1 now equals "overflow".
I do this:
#!/usr/bin/perl
$target = "n: 123";
my ($target) = $target =~ /n:\s*(\d+)/g;
print $target; # the var $target now is "123"
Also, to amplify the accepted answer using the ternary operator to allow you to specify a default if there is no match:
my $match = $variable =~ /(*pattern*).*/ ? $1 : *defaultValue*;