Get the value of a variable from another - perl

Can you assist me in determing correct $string = line to end up with partial_phone containing 4165867111?
sub phoneno {
my ($string) = #_;
$string =~ s/^\+*0*1*//g;
return $string;
}
my $phone = "<sip:+4165867111#something;tag=somethingelse>";
my $partial_phone = phoneno($phone);

$string =~ s{
\A # beginning of string
.+ # any characters
\+ # literal +
( # begin capture to $1
\d{5,} # at least five digits
) # end capture to $`
\# # literal #
.+ # any characters
\z # end of string
}{$1}xms;

Your substitution starts with a ^, which means it won't perform substitution unless the rest of your pattern matches the start of your string.
There are lots of ways to do this. How about
my ($partial) = $phone =~ /([2-9]\d+)/;
return $partial;
This returns any string of digits that doesn't begin with a 0 or 1.

This will capture all digits preceding the #:
use strict;
use warnings;
sub phoneno {
my ($string) = #_;
my ($phoneNo) = $string =~ /(\d+)\#/;
return $phoneNo;
}
my $phone = '<sip:+4165867111#something;tag=somethingelse>';
my $partial_phone = phoneno($phone);
print $partial_phone;
Output:
4165867111

Related

m operator of Regular Expression in Perl

What is the difference between m[] and m{} regular expression in Perl? How does $1, $2, etc matches the pattern "(((Cu)(Na))(Hg))"?
thanks
There is no difference between m{} and m[]. Perl lets you change the delimiters of regexes to make them easier to read in a given context.
$var =~ m/*.zip/ and $var =~ m{*.zip} and $var =~ m[*.zip] and $var =~ m#*.zip# all match the same way.
For capture groups, captures are always handled from left to right, so for your example:
my $foo = 'CuNaHg';
if ( $foo =~ m{(((Cu)(Na))(Hg))} ) {
print $1; # CuNaHg
print $2; # CuNa
print $3; # Cu
print $4; # Na
print $5; # Hg
}

Is there a better way to count occurrence of char in a string?

I felt there must a better way to count occurrence instead of writing a sub in perl, shell in Linux.
#/usr/bin/perl -w
use strict;
return 1 unless $0 eq __FILE__;
main() if $0 eq __FILE__;
sub main{
my $str = "ru8xysyyyyyyysss6s5s";
my $char = "y";
my $count = count_occurrence($str, $char);
print "count<$count> of <$char> in <$str>\n";
}
sub count_occurrence{
my ($str, $char) = #_;
my $len = length($str);
$str =~ s/$char//g;
my $len_new = length($str);
my $count = $len - $len_new;
return $count;
}
If the character is constant, the following is best:
my $count = $str =~ tr/y//;
If the character is variable, I'd use the following:
my $count = length( $str =~ s/[^\Q$char\E]//rg );
I'd only use the following if I wanted compatibility with versions of Perl older than 5.14 (as it is slower and uses more memory):
my $count = () = $str =~ /\Q$char/g;
The following uses no memory, but might be a bit slow:
my $count = 0;
++$count while $str =~ /\Q$char/g;
Counting the occurences of a character in a string can be performed with one line in Perl (as compared to your 4 lines). There is no need for a sub (although there is nothing wrong with encapsulating functionality in a sub). From perlfaq4 "How can I count the number of occurrences of a substring within a string?"
use warnings;
use strict;
my $str = "ru8xysyyyyyyysss6s5s";
my $char = "y";
my $count = () = $str =~ /\Q$char/g;
print "count<$count> of <$char> in <$str>\n";
In a beautiful* Bash/Coreutils/Grep one-liner:
$ str=ru8xysyyyyyyysss6s5s
$ char=y
$ fold -w 1 <<< "$str" | grep -c "$char"
8
Or maybe
$ grep -o "$char" <<< "$str" | wc -l
8
The first one works only if the substring is just one character long; the second one works only if the substrings are non-overlapping.
* Not really.
toolic has given a correct answer, but you might consider not hardcoding your values to make the program reusable.
use strict;
use warnings;
die "Usage: $0 <text> <characters>" if #ARGV < 1;
my $search = shift; # the string you are looking for
my $str; # the input string
if (#ARGV && -e $ARGV[0] || !#ARGV) { # if str is file, or there is no str
local $/; # slurp input
$str = <>; # use diamond operator
} else { # else just use the string
$str = shift;
}
my $count = () = $str =~ /\Q$search\E/gms;
print "Found $count of '$search' in '$str'\n";
This will allow you to use the program to count for the occurrence of a character, or a string, inside a string, a file, or standard input. For example:
count.pl needles haystack.txt
some_process | count.pl foo
count.pl x xyzzy

How to split with '|' in perl

the problem is that it return like split on undefined value
B
e
c
k
y
.
split string perl code
sub start_thread {
my #args = #_;
print('Thread started: ', #args, "\n");
open(my $myhandle,'<',#args) or die "unable to open file"; # typical open call
my #aftersplit;
for (;;) {
while (<$myhandle>) {
chomp;
#aftersplit = split('|',$_);
#print $_."\n";
foreach my $val (#aftersplit){
print $val."\n";
}
}
sleep 1;
seek FH, 0, 1; # this clears the eof flag on FH
}
}
it split the string in $_ and save in array aftersplit
You have to escape | as it is special char in regex,
my #aftersplit = split(/\|/, $_);
You need to escape special character | with \
#aftersplit = split('\|',$_);
You need to escape your delimiter, since it's a special character.
For certain special characters you need to precede your character with a literal \
my #aftersplit = split '\|', $_;
You can also use quotemeta.
my $separator = quotemeta('|');
my #aftersplit = split /$separator/, $_;
Or implement the escape sequence \Q
my #aftersplit = split /\Q|/, $_;

A Perl Program Which divides a String by spaces between them?

I want my program to divide the string by the spaces between them
$string = "hello how are you";
The output should look like that:
hello
how
are
you
You can do this is a few different ways.
use strict;
use warnings;
my $string = "hello how are you";
my #first = $string =~ /\S+/g; # regex capture non-whitespace
my #second = split ' ', $string; # split on whitespace
my $third = $string;
$third =~ tr/ /\n/; # copy string, substitute space for newline
# $third =~ s/ /\n/g; # same thing, but with s///
The first two creates arrays with the individual words, the last creates a different single string. If all you want is something to print, the last will suffice. To print an array do something like:
print "$_\n" for #first;
Notes:
Normally, regex capture requires parentheses /(\S+)/, but when the /g modifier is used, and parentheses are omitted, the entire match is returned.
When using capture this way, you need to assure list context on the assignment. If the left hand parameter is a scalar, you would force list context with parentheses: my ($var) = ...
I think like simple....
$string = "hello how are you";
print $_, "\n" for split ' ', $string;
#Array = split(" ",$string); then the #Array contain the answer
You need a split for dividing the string by spaces like
use strict;
my $string = "hello how are you";
my #substr = split(' ', $string); # split the string by space
{
local $, = "\n"; # setting the output field operator for printing the values in each line
print #substr;
}
Output:
hello
how
are
you
Split with regexp to account for extra spaces if any:
my $string = "hello how are you";
my #words = split /\s+/, $string; ## account for extra spaces if any
print join "\n", #words

Perl - How to change every $variable occurrence of ";" in a string

Very new here so be gentle. :)
Here is the jist of what I want to do:
I want to take a string that is made up of numbers separated by semi-colons (ex. 6;7;8;9;1;17;4;5;90) and replace every "X" number of semicolons with a "\n" instead. The "X" number will be defined by the user.
So if:
$string = "6;7;8;9;1;17;4;5;90";
$Nth_number_of_semicolons_to_replace = 3;
The output should be:
6;7;8\n9;1;17\n4;5;90
I've found lots on changing the Nth occurrence of something but I haven't been able to find anything on changing every Nth occurrence of something like I am trying to describe above.
Thanks for all your help!
use List::MoreUtils qw(natatime);
my $input_string = "6;7;8;9;1;17;4;5;90";
my $it = natatime 3, split(";", $input_string);
my $output_string;
while (my #vals = $it->()) {
$output_string .= join(";", #vals)."\n";
}
Here is a quick and dirty answer.
my $input_string = "6;7;8;9;1;17;4;5;90";
my $count = 0;
$input_string =~ s/;/++$count % 3 ? ";" : "\n"/eg;
Don't have time for a full answer now, but this should get you started.
$string = "6;7;8;9;1;17;4;5;90";
$Nth_number_of_semicolons_to_replace = 3;
my $regexp = '(' . ('\d+;' x ($Nth_number_of_semicolons_to_replace - 1)) . '\d+);';
$string =~ s{ $regexp ) ; }{$1\n}xsmg
sub split_x{
my($str,$num,$sep) = #_;
return unless defined $str;
$num ||= 1;
$sep = ';' unless defined $sep;
my #return;
my #tmp = split $sep, $str;
while( #tmp >= $num ){
push #return, join $sep, splice #tmp, 0, $num;
}
push #return, join $sep, #tmp if #tmp;
return #return;
}
print "$_\n" for split_x '6;7;8;9;1;17;4;5;90', 3
print join( ',', split_x( '6;7;8;9;1;17;4;5;90', 3 ) ), "\n";
my $string = "6;7;8;9;1;17;4;5;90";
my $Nth_number_of_semicolons_to_replace = 3;
my $num = $Nth_number_of_semicolons_to_replace - 1;
$string =~ s{ ( (?:[^;]+;){$num} [^;]+ ) ; }{$1\n}gx;
print $string;
prints:
6;7;8
9;1;17
4;5;90
The regex explained:
s{
( # start of capture group 1
(?:[^;]+;){$num} # any number of non ';' characters followed by a ';'
# repeated $num times
[^;]+ # any non ';' characters
) # end of capture group
; # the ';' to replace
}{$1\n}gx; # replace with capture group 1 followed by a new line
If you've got 5.10 or higher, this could do the trick:
#!/usr/bin/perl
use strict;
use warnings;
my $string = '1;2;3;4;5;6;7;8;9;0';
my $n = 3;
my $search = ';.*?' x ($n -1);
print "string before: [$string]\n";
$string =~ s/$search\K;/\n/g;
print "print string after: [$string]\n";
HTH,
Paul