my #array = (
'There were \d* errors that occurred',
'Your system exploded because \.*',
);
my $error = 'There were 22 errors that occurred';
if (grep(/$error/, #array)) {
print 'That error is ok, continue...';
} else {
die;
}
Is there any way in perl to compare a full string to a string containing regex?
Like in this example I'd want both $error = 'There were 22 errors that occurred' and $error = 'There were 12341235 errors that occurred' to be compared to a kind of "template" string and have a boolean returned if it matches. Using grep is probably not possible, I guess.
Maybe something like this that actually works:
my #s = ('there were \d* errors');
print _error_checker(#s, 'there were 10 errors');
sub _error_checker {
my (#acceptable_errors, $text) = #_;
foreach my $error (#acceptable_errors) {
if ($text =~ /$error/) {
return 1;
}
}
return 0;
}
You were close, you just need to invert your testing in the grep.
my #ok_errors = (
'There were \d* errors that occurred',
'Your system exploded because \.*',
);
my $errmsg = 'There were 22 errors that occurred';
if (grep {$errmsg =~ /$_/} #ok_errors) {
print 'That error is ok, continue...';
} else {
die;
}
Additionally, you can cache the regular expressions using qr{}
my #ok_errors = (
qr{There were \d* errors that occurred},
qr{Your system exploded because \.*},
);
my $errmsg = 'There were 22 errors that occurred';
if (grep {$errmsg =~ $_} #ok_errors) {
print 'That error is ok, continue...';
} else {
die;
}
Related
I have the following code in a subroutine in Perl for which I keep getting the following error :
Use of uninitialized value $nextLine in pattern match (m//) at catlist.pl line 67, line 2756.
sub extract_testdesc {
my #str = #_;
my $file = $_[0];
my $testname = $_[1];
my #fifo;
# Open the file
open( FILEHANDLE, $file ) or die "couldnt open";
while (<FILEHANDLE>) {
if ( $_ =~ m/\/\*\*/ ) { # if start of comment /**
undef(#fifo);
$nextLine = <FILEHANDLE>;
while ( $nextLine !~ m/\*\// ) { # Add all lines into array until */ is encountered
if ( $nextLine !~ m/\#testlogic.author/ ) {
$nextLine =~ s/\*//g;
if ( $nextLine ne "" ) {
push( #fifo, $nextLine );
}
}
$nextLine = <FILEHANDLE>;
}
}
if ( $_ =~ m/$testname/ ) {
return (#fifo);
}
}
close(FILEHANDLE);
}
What am I doing wrong ? I'm new to Perl so any help is appreciated.
Whenever you use a while loop on a file handle, it's actually synonymous with while (defined($_ = <FILEHANDLE>)) {. This is useful because once the filehandle reaches the eof, it will exit the loop. On the other hand, you are doing manual calls readline calls without testing to see if anything was returned, hence your uninitialized value warnings.
Overall, your goal and logic are confusing. However, perhaps an introduction to the range operator will help you? The following achieves what I think you logic is, but I easily could have misinterpreted.
sub extract_testdesc {
my ($file, $testname) = #_;
my #fifo;
# Open the file
open my $fh, '<', $file or die "couldnt open: $!";
while (<$fh>) {
if ( my $range = m{\Q/**} .. m{\Q*/}) {
#fifo = () if $range == 1;
push #fifo, $_;
} elsif ($_ =~ m/\Q$testname\E/ ) {
return (#fifo);
}
}
close($fh);
}
i have a perl script-
#!/usr/bin/perl;
my $email = '[a-zA-Z0-9._]+#[a-zA-Z0-9._]+.[a-zA-Z0-9._]{2,4}';
open(FILE,'emails');
while (<FILE>) {
my $emails_not_found = 1;
if ( m/$email/ ) {
print($_);
my $emails_not_found = 0;
}
if ( $emails_not_found ) {
print "no emails\n";
}
}
close FILE;
the file emails is:
sdfasd#asd
asdf
so, as you can see, the script will not match regex to any of the lines. however, it outputs this-
no emails
no emails
i want it to output 'no emails' ONCE if it doesn't match the regex pattern at all. If it only matches the regex pattern just once, it will print that line and output 'no emails' for the other
line :( I just want it to output either JUST the lines with the emails, or output 1 line that says 'no emails'. Thanks in advance.
Consider using a module, such as Regexp::Common::Email::Address, "...to match email addresses as defined by RFC 2822":
use strict;
use warnings;
use Regexp::Common qw/Email::Address/;
my $emailFound = 0;
open my $fh, '<', 'emails' or die $!;
while (<$fh>) {
if (/$RE{Email}{Address}/) {
print;
$emailFound = 1;
}
}
close $fh;
print "no emails\n" if !$emailFound;
Hope this helps!
Try this, I changed the emails file name in order to test on my machine:
#!/usr/bin/perl
#output either JUST the lines with emails
# or
#1 line that says 'no emails'
use strict;
use warnings;
my $email = '[a-z0-9\._]+#[a-z0-9\._]+\.[a-z0-9\._]{2,4}';
open(FILE,'./email.txt');
my $emails_not_found = 1;
while (<FILE>) {
if ( m/$email/i ) {
print($_);
$emails_not_found = 0;
}
}
if ( $emails_not_found == 1) {
print "no emails\n";
}
close FILE;
Test file
sdfasd#asd
asdf
aaa#aaa.com
AAA#AAA.COM
Output
aaa#aaa.com
AAA#AAA.COM
Now suppose say i have this line in a file:
my %address = (
or any such similar line in which i have defined the hash.
I want to find the character "(" in the line and store "address" in say $hash_name. How do I do it?
Basic idea is to capture the name of the hash defined in the files.
I am trying to do is,
foreach $line <MYFILE> {
if($line =~ /($/ {
How do I proceed further?
Not sure if I understood your problem, but, how about:
my %hash;
while (my $line = <MYFILE>) {
if ($line =~ /\%(\w+)\s*=\s*\($/) {
$hash{$1} = 1;
}
}
open (F1,"inputfile.txt") or die("unable to open inputfile.txt");
my $hash_name
while (<F1>) {
if (/%(\w+) *= *\(/) {
$hash_name = $1;
print $hash_name;
}
}
I have the next code:
$string = "hello to all world";
$strings_compare = tomorrow, hello, world;
$string_arrays =split(',',$strings_compare);
for ($i=0; $i<count($string_arrays); $i++){
$resultado = preg_match("/$string_arrays[$i]/",$string);
if($resultado == false){
echo "no match";
}else {
echo "match";
}
}
in this code the results are:
no match, match, no match
and the results should be: no match, match and match. What is my error?
if I change the $string by $string='say hello to all world now'
the results are match, match, match, this is OK.
It works fine for me when I'm using valid array syntax.
<?php
$string = "hello to all world";
$string_arrays = array("tomorrow", "hello", "world");
for ($i=0; $i<count($string_arrays); $i++) {
$resultado = preg_match("/$string_arrays[$i]/",$string);
if(!$resultado) {
echo "no match";
} else {
echo "match";
}
}
Returns
no matchmatchmatch
Try this:
$resultado = preg_match("/".preg_quote($string_arrays[$i])."/",$string);
Also:
$string_arrays = array("tomorrow", "hello", "world");
DON'T ASK WHY but...
I have a regex that needs to be case insensitive if run on windows BUT case sensitive when run on *nix.
Here is an example snippet of what I am kind-of doing at the moment.
sub relative_path
{
my ($root, $path) = #_;
if ($os eq "windows")
{
# case insensitive with regex option 'i'
if ($path !~ /^\Q$root\E[\\\/](.*)$/i)
{
print "\tFAIL:$root not in $path\n";
}
else
{
return $1;
}
}
else
{
# case sensitive
if ($path !~ /^\Q$root\E[\\\/](.*)$/)
{
print "\tFAIL:$root not in $path\n";
}
else
{
return $1;
}
}
return "";
}
Argh! The repetition hurts my OCD but my perl-fu is weak. Somehow I want to make the regex option 'i' for case-insensitive conditional but I don't now how?
You can use an extended construct to specify the option. For example:
#!/usr/bin/env perl
use warnings; use strict;
my $s = 'S';
print check($s, 'i'), "\n";
print check($s, '-i'), "\n";
sub check {
my ($s, $opt) = #_;
return "Matched" if $s =~ /(?$opt)^s\z/;
return "Did not match";
}
See perldoc perlre.
You can create patterns and store them in scalars using the qr operator:
sub relative_path
{
my ($root, $path) = #_;
my $pattern = ($os eq "windows") ? qr/^\Q$root\E[\\\/](.*)$/i : qr/^\Q$root\E[\\\/](.*)$/;
if ($path !~ $pattern)
{
print "\tFAIL:$root not in $path\n";
}
else
{
return $1;
}
}
This might not be 100% perfect, but hopefully you should get the idea.
Make sure to check out the section "Quote and Quote-Like Operators" in perlop.
EDIT: Okay, here's a DRY solution since people are complaining about it.
sub relative_path
{
my ($root, $path) = #_;
my $base_pattern = qr/^\Q$root\E[\\\/](.*)$/;
my $pattern = ($os eq "windows") ? qr/$base_pattern/i : $base_pattern;
if ($path !~ $pattern)
{
print "\tFAIL:$root not in $path\n";
}
else
{
return $1;
}
}
In addition to achieving the stated objective, this properly handles volumes unlike the regex patterns previously posted.
use Path::Class qw( dir );
sub relative_path {
my ($root, $path) = #_;
if ($^O =~ /Win32/) {
require Win32;
$root = Win32::GetLongPathName($root);
$path = Win32::GetLongPathName($path);
}
$root = dir($root);
$path = dir($path);
if ($root->subsumes($path)) {
return $path->relative($root);
} else {
print "\tFAIL:$root not in $path\n";
return "";
}
}
By the way, it's not very appropriate to handle the error there. The function should return an error signal (return undef, throw an exception, etc) and the caller should handle it as it sees fit. Separations of concerns.
You can also do it using local modifiers (perl extended regexes option):
sub relative_path
{
my ($root, $path) = #_;
my $pattern = "^\Q$root\E[\\\/](.*)$";
$pattern = "(?i)$pattern" if ($os eq "windows");
if ($path =~ /$pattern/)
{
return $1;
}
else
{
print "\tFAIL:$root not in $path\n";
}
}
(after I typed my answer I saw that Sinan also suggested it, but I decided to post my answer as well, since it gives a concreter answer to the question)