How to combine variables in string in Perl - string

$name = "LPA";
$date= 39;
$file = "/pathtoFile/window/$name/cavin_l/'$name'_formula_24rw$date.csv";
I want this to set $file equal to:
/pathtoFile/window/LPA/cavin_l/LPA_formula_24rw39.csv
But it is setting $file to:
/pathtoFile/window/LPA/cavin_l/'39.csv
Could someone help me figure out the correct syntax for what I am trying to accomplish? I cannot seem to get it.

You fell victim to the archaic ' (quote) package separator.
$name'_formula_24 is interpreted as $name::_formula24, and since that variable is undefined, the empty string is interpolated.
You should change that to
$file = "/pathtoFile/window/$name/cavin_l/${name}_formula_24rw$date.csv"
Quoting from the man perldata:
There are two package separators in Perl: A double colon ("::") and
a single quote ("'"). Normal identifiers can start or end with a
double colon, and can contain several parts delimited by double
colons. Single quotes have similar rules, but with the exception
that they are not legal at the end of an identifier: That is,
"$'foo" and "$foo'bar" are legal, but "$foo'bar'" is not.

The double quotes "..." interpolate variables in the string. Then the problem is that in your attempt the variable names in the string are not cleanly delineated† and the interpreter ends up looking for
$name::_formula_24rw
That is, the variable _formula_24rw in the package $name; this is because a ' after a variable name (so ' after $name in your $file) is still interpreted as a package separator ::, for historical reasons. As there is no such variable you end up with ' and then the value for $date.
The most important takeaway: use warnings; would have caught this. Try to run
use warnings;
use strict;
my $name = "LPA";
my $date= 39;
my $file = "/pathtoFile/window/$name/cavin_l/'$name'_formula_24rw$date.csv";
and it prints
Use of uninitialized value $name::_formula_24rw in concatenation (.) or string at ...
Please always have use warnings; and use strict; at the beginning of a program.
So either use ${...} where {} delimit the variable name
my $file = "/pathtoFile/window/$name/cavin_l/${name}_formula_24rw$date.csv";
or piece it together from separate strings
my $file = '/pathtoFile/window/'
. $name . '/cavin_l/' . $name . '_formula_24rw' . "$date.csv";
The . cannot be in a variable name so $date in that string is resolved correctly.†
† See identifier parsing in perldata for details on how variable names are parsed in code.

One way is to use curly braces around the variable name like this:
$file = "/pathtoFile/window/$name/cavin_l/${name}_formula_24rw$date.csv";
This syntax is described in perldoc perldata
As in some shells, you can enclose the variable name in braces to
disambiguate it from following alphanumerics (and underscores).

like most things in Perl there is many ways to do the same task.
You can use {} to define the boundaries of your variable name
my $file1="/pathtoFile/window/$name/cavin_l/${name}_formula_24rw$date.csv";
Alternatively you could use concatenation to join the string.
my $file2="/pathtoFile/window/$name/cavin_l/" . $name ."_formula_24rw" . $date . ".csv";
Both these methods produce the same result.
use strict;
use warnings;
my $name="LPA";
my $date="39";
my $file1="/pathtoFile/window/$name/cavin_l/${name}_formula_24rw$date.csv";
my $file2="/pathtoFile/window/$name/cavin_l/" . $name ."_formula_24rw" . $date . ".csv";
print "$file1\n$file2\n";
output
/pathtoFile/window/LPA/cavin_l/LPA_formula_24rw39.csv
/pathtoFile/window/LPA/cavin_l/LPA_formula_24rw39.csv

Related

Perl Program to Print Unicode From Hex Value

I am starting up with Perl and confused on how to render unicode characters given a hex string variable.
#!/usr/bin/perl
use warnings;
foreach my $i (0..10000) {
my $hex = sprintf("%X", $i);
print("unicode of $i is \x{$hex}\n");
}
print("\x{2620}\n");
print("\x{BEEF}\n");
Gives me the warning: Illegal hexadecimal digit '$' ignored at perl.pl line 9.
and no value prints for \x{$hex}
Both chr($num) and pack('W', $num) produce a string consisting of the single character with the specified value, just like "\x{XXXX}" does.
As such, you can use
print("unicode of $i is ".chr(hex($hex))."\n");
or just
print("unicode of $i is ".chr($i)."\n");
Note that your program makes no sense without
use open ':std', ':encoding(UTF-8)';
Yup. You can't do that. No variable interpolation allowed in the middle of a \x like that. You can use chr() to get that character though.
Randal's answer is correct. For more info, you might want to read perluniintro.
From there, you can find, for example:
At run-time you can use:
use charnames ();
my $hebrew_alef_from_name
= charnames::string_vianame("HEBREW LETTER ALEF");
my $hebrew_alef_from_code_point = charnames::string_vianame("U+05D0");

How to use Regex in Perl

I need some help , I have an output from a command and need to extract only the time i.e. "10:57:09" from the output.
The command is: tail -f /var/log/sms
command output:
Thu 2016/08/04 10:57:09 gammu-smsd[48014]: Read 0 messages
how could I do this in perl and put the result into variable
Thank you
Normally, we'd expect you to show some evidence of trying to solve the problem yourself before giving an answer.
You use the match operator (m/.../) to check if a string matches a regular expression. The m is often omitted so you'll see it written as /.../. By default, it matches against the variable $_ but you can change that by using the binding operator, =~. If a regex includes parentheses ((...)) then whatever is matched by that section of the regex is stored in $1 (and $2, $3, etc for subsequent sets of parentheses). Those "captured" values are also returned by the match operator when it is evaluated in list context.
It's always a good idea to check the return value from the match operator, as you'll almost certainly want to take different actions if the match was unsuccessful.
See perldoc perlop for more details of the match operator and perldoc perlre for more details of Perl's regex support.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
$_ = 'Thu 2016/08/04 10:57:09 gammu-smsd[48014]: Read 0 messages';
if (my ($time) = /(\d\d:\d\d:\d\d)/) {
say "Time is '$time'";
} else {
say 'No time found in string';
}
And to get the data from your external process...
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
open my $tail_fh, 'tail -f /var/log/sms |' or die $!;
while (<$tail_fh>) {
if (my ($time) = /(\d\d:\d\d:\d\d)/) {
say "Time is '$time'";
} else {
say 'No time found in string';
}
}
Perl code:
$txt = "Thu 2016/08/04 10:57:09 gammu-smsd[48014]: Read 0 messages";
$txt =~ /(\d{2}:\d{2}:\d{2})/;
print $1; # result of regex
print "\n"; # new line
And it prints:
10:57:09
The result goes to a variable called $1, due to the capturing parenthesis. Had there been more capturing parenthesis their captured text would have put int $2, $3 etc...
EDIT
To read the line from console, use in the above script:
$txt = <STDIN>;
Now, suppose the script is called myscript.pl, execute tail like so:
tail -f /var/log/sms | myscript.pl

perl extract numbers from string, edit, put back into string at their original position

I'm trying to edit the numbers in a string and put it back in the same place as they have been before.
Example:
$string = "struct:{thin:[[75518103,75518217],[75518338,75518363],[75532810,75533910],],thick:[[75518363,75518424],[75521257,75521463],],}";
I need to edit the numbers, but want to keep the rest of the string at it is. Additionally the number of brackets can vary.
Until now I split the string at "," with
#array = split (',',$string);
and extracted the numbers for editing with
foreach (#array) {
$_ =~ s/\D//g;
$_ = $number - $_;
}
now I want to put the numbers back in their original place in the string, but I don't know how.
Somehow I hope there is a better way to edit the numbers in the string without splitting it and extracting the numbers. Hope you can help me
You could use a regular expression substitution with the /e flag, search for long numbers and run Perl code in the substitution part.
use strict;
use warnings;
use feature 'say';
my $number = 100_000_000;
my $string = "struct:{thin:[[75518103,75518217],[75518338,75518363],[75532810,75533910],],thick:[[75518363,75518424],[75521257,75521463],],}";
$string =~ s/(\d+)/{$number - $1}/eg;
say $string;
__END__
struct:{thin:[[24481897,24481783],[24481662,24481637],[24467190,24466090],],thick:[[24481637,24481576],[24478743,24478537],],}
If there are no other numbers in the string, that would work. In case there is more logic involved, you can also move it into a subroutine and just call that in the substitution.
sub replace {
return $_ % 2 ? $_ * 2 : $_ / 4;
}
$string =~ s/(\d+)/{replace($1)}/eg;
You might also need to revise the search pattern to be a bit more precise.
I just found the evaluation modifier for regex! I now did it with
$string =~ s/([0-9]+)/$number-$1/eg;
and it worked!

How to concatenate variables in Perl

Is there a different way to concatenate variables in Perl?
I accidentally wrote the following line of code:
print "$linenumber is: \n" . $linenumber;
And that resulted in output like:
22 is:
22
I was expecting:
$linenumber is:
22
So then I wondered. It must be interpreting the $linenumber in the double quotes as a reference to the variable (how cool!).
What are the caveats to using this method and how does this work?
Variable interpolation occurs when you use double quotes. So, special characters need to be escaped. In this case, you need to escape the $:
print "\$linenumber is: \n" . $linenumber;
It can be rewritten as:
print "\$linenumber is: \n$linenumber";
To avoid string interpolation, use single quotes:
print '$linenumber is: ' . "\n$linenumber"; # No need to escape `$`
I like .= operator method:
#!/usr/bin/perl
use strict;
use warnings;
my $text .= "... contents ..."; # Append contents to the end of variable $text.
$text .= $text; # Append variable $text contents to variable $text contents.
print $text; # Prints "... contents ...... contents ..."
If you change your code from
print "$linenumber is: \n" . $linenumber;
to
print '$linenumber is:' . "\n" . $linenumber;
or
print '$linenumber is:' . "\n$linenumber";
it will print
$linenumber is:
22
What I find useful when wanting to print a variable name is to use single quotes so that the variables within will not be translated into their value making the code easier to read.
In Perl any string that is built with double quotes will be interpolated, so any variable will be replaced by its value. Like many other languages if you need to print a $, you will have to escape it.
print "\$linenumber is:\n$linenumber";
OR
print "\$linenumber is:\n" . $linenumber;
OR
printf "\$linenumber is:\n%s", $linenumber;
Scalar Interpolation
When formulating this response, I found this webpage which explains the following information:
###################################################
#Note that when you have double quoted strings, you don't always need to concatenate. Observe this sample:
#!/usr/bin/perl
$a='Big ';
$b='Macs';
print 'I like to eat ' . $a . $b;
#This prints out:
# I like to eat Big Macs
###################################################
#If we had used double quotes, we could have accomplished the same thing like this:
#!/usr/bin/perl
$a='Big ';
$b='Macs';
print "I like to eat $a $b";
#Printing this:
# I like to eat Big Macs
#without having to use the concatenating operator (.).
###################################################
#Remember that single quotes do not interpret, so had you tried that method with single quotes, like this:
#!/usr/bin/perl
$a='Big ';
$b='Macs';
print 'I like to eat $a $b';
#Your result would have been:
# I like to eat $a $b
#Which don't taste anywhere near as good.
I thought this would be helpful to the community so I'm asking this and answering my own question. Other helpful answers are more than welcome!
You can backslash the $ to print it literally:
print "\$linenumber is: \n" . $linenumber;
That prints what you were expecting. You can also use single quotes if you don't want Perl to interpolate variable names, but then the "\n" will be interpolated literally.

Printing string in Perl

Is there an easy way, using a subroutine maybe, to print a string in Perl without escaping every special character?
This is what I want to do:
print DELIMITER <I don't care what is here> DELIMITER
So obviously it will great if I can put a string as a delimiter instead of special characters.
perldoc perlop, under "Quote and Quote-like Operators", contains everything you need.
While we usually think of quotes as literal values, in Perl they function as operators, providing various kinds of interpolating and pattern matching
capabilities. Perl provides customary quote characters for these behaviors, but also provides a way for you to choose your quote character for any of
them. In the following table, a "{}" represents any pair of delimiters you choose.
Customary Generic Meaning Interpolates
'' q{} Literal no
"" qq{} Literal yes
`` qx{} Command yes*
qw{} Word list no
// m{} Pattern match yes*
qr{} Pattern yes*
s{}{} Substitution yes*
tr{}{} Transliteration no (but see below)
<<EOF here-doc yes*
* unless the delimiter is ''.
$str = q(this is a "string");
print $str;
if you mean quotes and apostrophes with 'special characters'
You can use the __DATA__ directive which will treat all of the following lines as a file that can be accessed from the DATA handle:
while (<DATA>) {
print # or do something else with the lines
}
__DATA__
#!/usr/bin/perl -w
use Some::Module;
....
or you can use a heredoc:
my $string = <<'END'; #single quotes prevent any interpolation
#!/usr/bin/perl -b
use Some::Module;
....
END
The printing is not doing special things to the escapes, double quoted strings are doing it. You may want to try single quoted strings:
print 'this is \n', "\n";
In a single quoted string the only characters that must be escaped are single quotes and a backslash that occurs immediately before the end of the string (i.e. 'foo\\').
It is important to note that interpolation does not work with single quoted strings, so
print 'foo is $foo', "\n";
Will not print the contents of $foo.
You can pretty much use any character you want with q or qq. For example:
#!/usr/bin/perl
use utf8;
use strict; use warnings;
print q∞This is a test∞;
print qq☼\nThis is another test\n☼;
print q»But, what is the point?»;
print qq\nYou are just making life hard on yourself!\n;
print qq¿That last one is tricky\n¿;
You cannot use qq DELIMITER foo DELIMITER. However, you could use heredocs for a similar effect:
print <<DELIMITER
...
DELIMETER
;
or
print <<'DELIMETER'
...
DELIMETER
;
but your source code would be really ugly.
If you want to print a string literally and you have Perl 5.10 or later then
say 'This is a string with "quotes"' ;
will print the string with a newline.. The importaning thing is to use single quotes ' ' rather than double ones " "

Resources