unable to check for a pattern in a string - perl

All I want to check is that whether "free" occurs in word boundary or not and this is not working(prints nothing):
use strict;
my #words= ("free hotmail msn");
my $free = "free";
$free =~ s/.*/\b$&\b/;
if ( $words[0] =~ m/$free/)
{
print "found\n";
}

All you need to do is write
my $free = 'free';
$free = qr/\b$free\b/;
print "found" if $words[0] =~ $free;
But if your #words array is supposed to contain a single word per element then you are more likely to want
use strict;
use warnings;
my #words= qw( free hotmail msn );
my $free = "free";
print "found\n" if $words[0] eq $free;

In a pattern replacement, as in a double quoted string, \b is interpreted as the backspace character (chr(8) on most systems).
$free =~ s/.*/\\b$&\\b/;
is an awkward way of writing one of
$free = '\b' . $free . '\b';
$free = "\\b$free\\b";
but it will do the job.

Related

Split to get only characters in Perl

I have a string like this :
Reporting EXE1 BASE,Normal
I need to get a var for every words like :
$info = "Reporting";
$host = "EXE1";
$device = "BASE";
$status = "Normal";
In fact, i saw the function "Split" might be a good use, but i don't understand the patern to use.
I prefer to use a global regex pattern match instead of split. That way you can specify the characters that you're interested in instead of the ones that you want to discard, and there's no chance of a spurious initial empty field if your string happens to start with a separator
It looks like you want to pick out "word" characters, which are upper and lower case letters, decimal digits, and the underscore character. There's a built-in character class \w for that, so finding all sequences that match \w+ should find the data for you
Here's an example program
use strict;
use warnings 'all';
my $s = 'Reporting EXE1 BASE,Normal';
my ( $info, $host, $device, $status ) = $s =~ /\w+/g;
print qq{\$info = "$info"\n};
print qq{\$host = "$host"\n};
print qq{\$device = "$device"\n};
print qq{\$status = "$status"\n};
output
$info = "Reporting"
$host = "EXE1"
$device = "BASE"
$status = "Normal"
If you want to allow more characters than \w matches then you could use
my ( $info, $host, $device, $status ) = $s =~ /[^\s,]+/g;
which matches sequences of characters that are neither space nor comma
Given your sample data the results are identical, but I cannot tell what your real data looks like
Use split(/\s|,/,"Reporting EXE1 BASE,Normal") to split the string on comma and blank
You might try this code.
my $str = "Reporting EXE1 BASE,Normal";
my #fields = split /\s|,/, $str;
my $info = $fields[0];
my $host = $fields[1];
my $device = $fields[2];
my $status = $fields[3];
print "$info\n";
print "$host\n";
print "$device\n";
print "$status\n";
Or more compact version -
my $str = "Reporting EXE1 BASE,Normal";
my ( $info, $host, $device, $status ) = split /[\s,]/, $str ;
print "$info\n";
print "$host\n";
print "$device\n";
print "$status\n";
No need to store the data in an array. Directly create the list and give the variable name to it.
my $string = "Reporting EXE1 BASE,Normal";
my ($info ,$host,$device,$status) = split(/\s|,/,$string);
print "$info ,$host,$device,$status";
Or else you could use pattern matching
my ($info ,$host,$device,$status) = $string =~m/(\w+)/g;

Perl: how to split string without storing into array and continue split?

I guess this has been asked before, but I can't find it.
Say
my $string = "something_like:this-and/that";
my #w1 = split(/_/, $string);
my #w2 = split(/-/, $w1[1]);
my #w3 = split(/:/, $w2[0]);
print $w3[1]; #print out "this"
Is there anyway to avoid the temporary array variables #w1, #w2 and #w3 and get $w3[1] directly? I remember continue split works, but forget the syntax.
Thanks.
Yes, it's possible, but would be much harder to read, so isn't advised:
my $string = "something_like:this-and/that";
my $this = (split /:/, (split /-/, (split(/_/, $string))[1])[0])[1];
print $this; #print out "this"
Alternatively, you could use a regex in this instance, but don't think it adds anything:
my $string = "something_like:this-and/that";
my ($this) = $string =~ /.*?_.*?:([^-]*)/ or warn "not found";
print $this;
Your own solution unnecessarily splits on underscores, unless your real data is significantly different from your example. You could write this
use strict;
use warnings;
my $string = "something_like:this-and/that";
my $value = (split /-/, (split /:/, $string)[1])[0];
print $value;
Or this solution uses regular expressions and does what you ask
use strict;
use warnings;
my $string = "something_like:this-and/that";
my ($value) = $string =~ /:([^_-]*)/;
print $value;
output
this
This will modify $string in place:
my $string = "something_like:this-and/that";
$string =~ s/^.*:(.+)-.*/$1/;

Perl: long string conversion to comma delimited list of bytes

I want to convert ABCDEF to A,B,C,D,E,F
What is the fastest way to do this using Perl?
I have lots of strings to convert and the strings can be up to 32768 bytes long. So, I want to lower the overhead from the string conversion.
How about
$string =~ s/.\K(?=.)/,/g; # using \K keep escape
$string =~ s/(?<=.)(?=.)/,/g; # pure lookaround assertion
Or
$string = join ",", split(//, $string);
To find the fastest solution, use Benchmark.
Extra credit:
This is the result of a benchmark I tried. Surprisingly, the \K escape is much faster than the pure lookaround, which is about as fast as the split/join.
use strict;
use warnings;
use Benchmark qw(cmpthese);
my $string = "ABCDEF" x 1000;
cmpthese(-1, {
keep => 'my $s = $string; $s =~ s/.\K(?=.)/,/g',
lookaround => 'my $s = $string; $s =~ s/(?<=.)(?=.)/,/g',
splitjoin => 'my $s = $string; $s = join ",", split(//, $string)'
});
Output:
Rate splitjoin lookaround keep
splitjoin 6546367/s -- -6% -47%
lookaround 6985568/s 7% -- -44%
keep 12392841/s 89% 77% --
$ perl -le 'print join(",", unpack("(A)*", "hello"))'
h,e,l,l,o
$ perl -le 'print join(",", unpack("C*", "hello"))'
104,101,108,108,111
$ perl -le 'print join(",", unpack("(H2)*", "hello"))'
68,65,6c,6c,6f
my $str = "ABCDEFGHIJKL";
my #chars = $str =~ /./sg;
print join ",", #chars;
If you're trying to print strings with lower overhead, you may want to just print the string while you parse it, rather than doing the whole transformation in memory, i.e.
while (m/(.)\B/gc){
print "$1,";
};
if (m/\G(.)/) {
print "$1\n";
}

perl find and replace ../ and  

I am using Perl to replace all instances of
../../../../../../abc' and  
in a string with
/ and , respectively.
The method I am using looks like this:
sub encode
{
my $result = $_[0];
$result =~ s/..\/..\/..\/..\/..\/..\//\//g;
$result =~ s/ / /g;
return $result;
}
Is this correct?
Essentially, yes, although the first regex has to be written in a different way: because . matches any character, we have to escape it \. or put it in its own character class [.]. The first regex can also be written cleaner as
...;
$result =~ s{ (?: [.][.]/ ){6} }
{/}gx;
...;
We look for the literal pattern ../ repeated 6 times and then replace it. Because I use curly braces as a delimiter I don't have to escape the slash. Because I use the /x modifier I can have these spaces inside the regex improving readability.
Try this. It will print /foo bar/baz.
#!/usr/bin/perl -w
use strict;
my $result = "../../../../../../foo bar/baz";
#$result =~ s/(\.\.\/)+/\//g; #for any number of ../
$result =~ s/(\.\.\/){6}/\//g; #for 6 exactly
$result =~ s/ / /g;
print $result . "\n";
you forgot the abc, i think:
sub encode
{
my $result = $_[0];
$result =~ s/(?:..\/){6}abc/\//g;
$result =~ s/ / /g;
return $result;
}

Check for spaces in perl using regex match in perl

I have a variable how do I use the regex in perl to check if a string has spaces in it or not ? For ex:
$test = "abc small ThisIsAVeryLongUnbreakableStringWhichIsBiggerThan20Characters";
So for this string it should check if any word in the string is not bigger than some x characters.
#!/usr/bin/env perl
use strict;
use warnings;
my $test = "ThisIsAVeryLongUnbreakableStringWhichIsBiggerThan20Characters";
if ( $test !~ /\s/ ) {
print "No spaces found\n";
}
Please make sure to read about regular expressions in Perl.
Perl regular expressions tutorial - perldoc perlretut
You should have a look at the perl regex tutorial. Adapting their very first "Hello World" example to your question would look like this:
if ("ThisIsAVeryLongUnbreakableStringWhichIsBiggerThan20Characters" =~ / /) {
print "It matches\n";
}
else {
print "It doesn't match\n";
}
die "No spaces" if $test !~ /[ ]/; # Match a space
die "No spaces" if $test =~ /^[^ ]*\z/; # Match non-spaces for entire string
die "No whitespace" if $test !~ /\s/; # Match a whitespace character
die "No whitespace" if $test =~ /^\S*\z/; # Match non-whitespace for entire string
To find the length of the longest unbroken sequence of non-space characters, write this
use strict;
use warnings;
use List::Util 'max';
my $string = 'abc small ThisIsAVeryLongUnbreakableStringWhichIsBiggerThan20Characters';
my $max = max map length, $string =~ /\S+/g;
print "Maximum unbroken length is $max\n";
output
Maximum unbroken length is 61