Split to get only characters in Perl - 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;

Related

How to separate an array in Perl based on pattern

I am trying to write a big script but I am stuck on a part. I want to sprit an array based on ".."
From the script I got this:
print #coordinates;
gene complement(872..1288)
my desired output:
complement 872 1288
I tried:
1) my #answer = split(.., #coordinates)
print("#answer\n");
2) my #answer = split /../, #coordinates;
3) print +(split /\../)[-1],[-2],[-3] while <#coordinates>
4) foreach my $anwser ( #coordinates )
{$anwser =~ s/../"\t"/;
print $anwser;}
5) my #answer = split(/../, "complement(872..1288)"); #to see if the printed array is problematic.
which prints:
) ) ) ) ) ) ) ) )
6) my #answer = split /"gene "/, #coordinates; # I tried to "catch" the entire output's spaces and tabs
which prints
0000000000000000000000000000000001000000000100000000
But none of them works. Does anyone has any idea how to step over this issue?
Ps, unfortunately, I can't run my script right now on Linux so I used this website to run my script. I hope this is not the reason why I didn't get my desired output.
my $RE_COMPLEMENT = qr{(complement)\((\d+)\.\.(\d+)\)}msx;
for my $item (#coordinates) {
my ($head, $i, $j) = $item =~ $RE_COMPLEMENT;
if (defined($head) && defined($i) && defined($j)) {
print("$head\t$i\t$j\n");
}
}
split operates on a scalar, not on an array.
my $string = 'gene complement(872..1288)';
my #parts = split /\.\./, $string;
print $parts[0]; # gene complement(872
print $parts[1]; # 1288)
To get the desired output, you can use a substitution:
my $string = 'gene complement(872..1288)';
$string =~ s/gene +|\)//g;
$string =~ s/\.\./ /;
$string =~ s/\(/ /;
Desired effect can be achieved with
use of tr operator to replace '(.)' => ' '
then splitting data string into element on space
storing only required part of array
output elements of array joined with tabulation
use strict;
use warnings;
use feature 'say';
my $data = <DATA>;
chomp $data;
$data =~ tr/(.)/ /;
my #elements = (split ' ', $data)[1..3];
say join "\t", #elements;
__DATA__
gene complement(872..1288)
Or as an alternative solution with only substitutions (without splitting data string into array)
use strict;
use warnings;
use feature 'say';
my $data = <DATA>;
chomp $data;
$data =~ s/gene\s+//;
$data =~ s/\)//;
$data =~ s/[(.]+/\t/g;
say $data;
__DATA__
gene complement(872..1288)
Output
complement 872 1288

How can I extract the number from the output of a shell command?

The output for the command is ent3, and from that output I want 3 to be stored in a variable
Perl code
sub {
if ( $exit == 1 )
{
$cmdStr = "lsdev | grep en | grep VLAN | awk '{ print \$1 }'\r";
$result =_run_cmd($cmdStr);
my #PdAt_val = split("\r?\n", $result);
my $num = $result =~ /([0-9]+)/;
print "The char is $num\n";
$exit = 0;
exp_continue;
Tidied code
sub {
if ( $exit == 1 ) {
$cmdStr = "lsdev | grep en | grep VLAN | awk '{ print \$1 }'\r";
$result = _run_cmd($cmdStr);
my #PdAt_val = split("\r?\n", $result);
my $num = $result =~ /([0-9]+)/;
print "The char is $num\n";
$exit = 0;
exp_continue;
Your code that is doing the work here is:
my $num = $result =~ /([0-9]+)/;
Let's put that into a simple program so we can see what's going on.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
my $result = 'ext3';
my $num = $result =~ /([0-9]+)/;
say $num;
And that prints 1. Which isn't what we want. What's going on?
Well, if you read the documentation for the match operator (in the section Regexp Quote-Like Operators in "perlop"), you'll see what the operator returns under different circumstances. It says:
Searches a string for a pattern match, and in scalar context returns true if it succeeds, false if it fails.
So that explains the behaviour we're seeing. That "1" is just a true value saying that the match succeeded. But how do we get the value that we have captured in our parentheses. There are a couple of ways. Firstly, it's written into the $1 variable.
my $num;
if ($result =~ /([0-9]+)/) {
$num = $1;
}
say $num;
But I think the other approach is what you were looking for. If you read on, you'll see what the operator returns in list context:
m// in list context returns a list consisting of the subexpressions matched by the parentheses in the pattern, that is, ($1, $2, $3 ...)
So if we put the match operator in list context, then we'll get the contents of $1 returned. How do we put a match into list context? By making the expression a list assignment - which we can do by putting parentheses around the left-hand side of the assignment.
my ($num) = $result =~ /([0-9]+)/;
say $num;
Using regex, something like this should work:
if($result =~ /([0-9]+)/) {
$num = $1;
}
print $num;

Remove all characters except "all" or "ALL"

I have string like this
$input = "ALL112343" or $input = "all11234" or $input = "ALL 1234"
my expect output would be
$input = "ALL" or $input = "all"
so, how can I remove all the character in that string except the word "all" or "ALL"?
Thank you all for your help,
You want
($input) = $input =~ /(all)/i;
If there can only be one occurrence of all or ALL:
$input = $input =~ /(all|ALL)/ ? $1 : "";
If there can be multiple occurrences of all or ALL:
$input =~ s/\G(?:all|ALL)*\K.//sg;
$input = join('', $input =~ /all|ALL/g );
It might be more useful to have an array of matches:
my #matches = $input =~ /all|ALL/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/;

unable to check for a pattern in a string

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.