perl + #ARGV + print syntax - perl

How to print the number of arguments from #ARGV
according to the following script why its important to print
like
print q{don't have parameters};
And not as
print "don't have parameters"; ??
lidia
#!/usr/bin/perl
if (#ARGV) {
print ......
} else {
print q{don't have parameters};
}

To print the number of elements in any array in perl:
print scalar(#ARGV);
Using q{} OR single quotes '' means that a string will get quoted but NOT interpolated, meaning any variables you have inside will not have their actual values. This is a faster way to create strings than with double quotes "" or qq{} which WILL interpolate variables in the string.

moreover, print q{} is a shorthand for :
print 'don\'t have parameters'
double quotes mean your string gets interpolated. ie : perl analysis it to retrieve
variable values.
simple quotes won't. No unrequired analysis -> faster, less memory/cpu/whatever usage

Related

Why are my double quotes are missing in the output?

I tried to convert strings from lower case to upper case. While I achieved that, I found my double quotes were removed from the output. I want to be clear why the substitution fails here.
Perl code:
#!/usr/bin/perl
use strict;
use warnings;
my #ar = <DATA>;
my $str = join '', #ar;
#print $str;
if ( $str =~ s/\"([^"]*)\"/uc($1)/eg ) {
print $str;
}
__DATA__
output = " as (10) print "it if achieved. print" # This is comment.NUMBERS"
Obtained output:
output = AS (10) PRINT it if achieved. print # THIS IS COMMENT.NUMBERS
Expected output:
output = " AS (10) PRINT "it if achieved. print" # THIS IS COMMENT.NUMBERS"
The quotes are all disappearing because they're outside the capture in your regex. Changing it to s/("[^"]*")/uc($1)/eg gets us your desired output:
output = " AS (10) PRINT "it if achieved. print" # THIS IS COMMENT.NUMBERS"
Note that the inner section isn't mapped to all caps. This is a hint to how the regex is actually matching things in your string - it finds two matches: " as (10) print " and " # This is comment.NUMBERS". The text inside the inner quotes isn't matched by the regex at all. This is important, because it means that this solution is fragile and it will break on data which doesn't contain two nested sets of quotes and you want to capitalize only the text which is inside the outer quotes, but outside the inner quotes.
s/\"([^"]*)\"/uc($1)/eg - $1 represents match inside brackets (). You have include double quotes in match to be replaced but outside brackets.
Possible fix:
s/(\"[^"]*\")/uc($1)/eg

print lines after finding a key word in perl

I have a variable $string and i want to print all the lines after I find a keyword in the line (including the line with keyword)
$string=~ /apple /;
I'm using this regexp to find the key word but I do not how to print lines after this keyword.
It's not really clear where your data is coming from. Let's assume it's a string containing newlines. Let's start by splitting it into an array.
my #string = split /\n/, $string;
We can then use the flip-flop operator to decide which lines to print. I'm using \0 as a regex that is very unlikely to match any string (so, effectively, it's always false).
for (#string) {
say if /apple / .. /\0/;
}
Just keep a flag variable, set it to true when you see the string, print if the flag is true.
perl -ne 'print if $seen ||= /apple/'
If your data in scalar variable we can use several methods
Recommended method
($matching) = $string=~ /([^\n]*apple.+)/s;
print "$matching\n";
And there is another way to do it
$string=~ /[^\n]*apple.+/s;
print $&; #it will print the data which is match.
If you reading the data from file, try the following
while (<$fh>)
{
if(/apple/)
{
print <$fh>;
}
}
Or else try the following one liner
perl -ne 'print <> and exit if(/apple/);' file.txt

How can I prevent Perl from interpreting double-backslash as single-backslash character?

How can I print a string (single-quoted) containing double-backslash \\ characters as is without making Perl somehow interpolating it to single-slash \? I don't want to alter the string by adding more escape characters also.
my $string1 = 'a\\\b';
print $string1; #prints 'a\b'
my $string1 = 'a\\\\b';
#I know I can alter the string to escape each backslash
#but I want to keep string as is.
print $string1; #prints 'a\\b'
#I can also use single-quoted here document
#but unfortunately this would make my code syntactically look horrible.
my $string1 = <<'EOF';
a\\b
EOF
print $string1; #prints a\\b, with newline that could be removed with chomp
The only quoting construct in Perl that doesn't interpret backslashes at all is the single-quoted here document:
my $string1 = <<'EOF';
a\\\b
EOF
print $string1; # Prints a\\\b, with newline
Because here-docs are line-based, it's unavoidable that you will get a newline at the end of your string, but you can remove it with chomp.
Other techniques are simply to live with it and backslash your strings correctly (for small amounts of data), or to put them in a __DATA__ section or an external file (for large amounts of data).
If you are mildly crazy, and like the idea of using experimental software that mucks about with perl's internals to improve the aesthetics of your code, you can use the Syntax::Keyword::RawQuote module, on CPAN since this morning.
use syntax 'raw_quote';
my $string1 = r'a\\\b';
print $string1; # prints 'a\\\b'
Thanks to #melpomene for the inspiration.
Since the backslash interpolation happens in string literals, perhaps you could declare your literals using some other arbitrary symbol, then substitute them for something else later.
my $string = 'a!!!b';
$string =~ s{!}{\\}g;
print $string; #prints 'a\\\b'
Of course it doesn't have to be !, any symbol that does not conflict with a normal character in the string will do. You said you need to make a number of strings, so you could put the substitution in a function
sub bs {
$_[0] =~ s{!}{\\}gr
}
my $string = 'a!!!b';
print bs($string); #prints 'a\\\b'
P.S.
That function uses the non-destructive substitution modifier /r introduced in v5.14. If you are using an older version, then the function would need to be written like this
sub bs {
$_[0] =~ s{!}{\\}g;
return $_[0];
}
Or if you like something more readable
sub bs {
my $str = shift;
$str =~ s{!}{\\}g;
return $str;
}

Perl tr operator is transliterating based on the variable's name not its value

I'm using Perl 5.16.2 to try to count the number of occurrences of a particular delimiter in the $_ string. The delimiter is passed to my Perl program via the #ARGV array. I verify that it is correct within the program. My instruction to count the number of delimiters in the string is:
$dlm_count = tr/$dlm//;
If I hardcode the delimiter, e.g. $dlm_count = tr/,//; the count comes out correctly. But when I use the variable $dlm, the count is wrong. I modified the instruction to say
$dlm_count = tr/$dlm/\t/;
and realized from how the tabs were inserted in the string that the operation was substituting every instance of any of the four characters "$", "d", "l", or "m" to \t — i.e. any of the four characters that made up my variable name $dlm.
Here is a sample program that illustrates the problem:
$_ = "abcdefghij,klm,nopqrstuvwxyz";
my $dlm = ",";
my $dlm_count = tr/$dlm/\t/;
print "The count is $dlm_count\n";
print "The modified string is $_\n";
There are only two commas in the $_ string, but this program prints the following:
The count is 3
The modified string is abc efghij,k ,nopqrstuvwxyz
Why is the $dlm token being treated as a literal string of four characters instead of as a variable name?
You cannot use tr that way, it doesn't interpolate variables. It runs strictly character by character replacement. So this
$string =~ tr/a$v/123/
is going to replace every a with 1, every $ with 2, and every v with 3. It is not a regex but a transliteration. From perlop
Because the transliteration table is built at compile time, neither the SEARCHLIST nor the REPLACEMENTLIST are subjected to double quote interpolation. That means that if you want to use variables, you must use an eval():
eval "tr/$oldlist/$newlist/";
die $# if $#;
eval "tr/$oldlist/$newlist/, 1" or die $#;
The above example from docs hints how to count. For $dlms in $string
$dlm_count = eval "\$string =~ tr/$dlm//";
The $string is escaped so to not be interpolated before it gets to eval. In your case
$dlm_count = eval "tr/$dlm//";
You can also use tools other than tr (or regex). For example, with string being in $_
my $dlm_count = grep { /$dlm/ } split //;
When split breaks $_ by the pattern that is empty string (//) it returns the list of all characters in it. Then the grep block tests each against $dlm so returning the list of as many $dlm characters as there were in $_. Since this is assigned to a scalar, $dlm_count is set to the length of that list, which is the count of all $dlm.
In the section of the docs on perlop 'Quote Like Operators', it states:
Because the transliteration table is built at compile time, neither
the SEARCHLIST nor the REPLACEMENTLIST are subjected to double quote
interpolation. That means that if you want to use variables, you must
use an eval():
As documented and as you discovered, tr/// doesn't interpolate. The simple solution is to use s/// instead.
my $dlm = ",";
$_ = "abcdefghij,klm,nopqrstuvwxyz";
my $dlm_count = s/\Q$dlm/\t/g;
If the transliteration is being performed in a loop, the following might speed things up noticeably:
my $dlm = ",";
my $tr = eval "sub { tr/\Q$dlm\E/\\t/ }";
for (...) {
my $dlm_count = $tr->();
...
}
Although several answers have hinted at the eval() idiom for tr///, none have the form that covers cases where the string has tr syntax characters in it, e.g.- (hyphen):
$_ = "abcdefghij,klm,nopqrstuvwxyz";
my $dlm = ",";
my $dlm_count = eval sprintf "tr/%s/%s/", map quotemeta, $dlm, "\t";
But as others have noted, there are lots of ways to count characters in Perl that avoid eval(), here's another:
my $dlm_count = () = m/$dlm/go;

How to convert single quoted string to double quoted string so it gets interpreted?

For example I have,
my $str = '\t';
print "My String is ".$str;
I want the output to interpret the tab character and return something like:
"My String is \t"
I am actually getting the value of the string from the database, and it returns it as a single quoted string.
String::Interpolate does exactly that
$ perl -MString::Interpolate=interpolate -E 'say "My String is [". interpolate(shift) . "]"' '\t'
My String is [ ]
'\t' and "\t" are string literals, pieces of Perl code that produces strings ("\","t" and the tab character respectively). The database doesn't return Perl code, so describing the problem in terms of single-quoted literals and double-quoted literals makes no sense. You have a string, period.
The string is formed of the characters "\" and "t". You want to convert that sequence of characters into the tab character. That's a simple substitution.
s/\\t/\t/g
I presume you don't want to deal with just \t. You can create a table of the sequences.
my %escapes = (
"t" => "\t",
"n" => "\n",
"\" => "\\",
);
my $escapes_pat = join('', map quotemeta, keys(%escapes));
$escapes_pat = qr/[$escapes_pat]/;
s/\\($escapes_pat)/$escapes{$1}/g;
You can follow the technique in perlfaq4's answer to How can I expand variables in text strings?:
If you can avoid it, don't, or if you can use a templating system, such as Text::Template or Template Toolkit, do that instead. You might even be able to get the job done with sprintf or printf:
my $string = sprintf 'Say hello to %s and %s', $foo, $bar;
However, for the one-off simple case where I don't want to pull out a full templating system, I'll use a string that has two Perl scalar variables in it. In this example, I want to expand $foo and $bar to their variable's values:
my $foo = 'Fred';
my $bar = 'Barney';
$string = 'Say hello to $foo and $bar';
One way I can do this involves the substitution operator and a double /e flag. The first /e evaluates $1 on the replacement side and turns it into $foo. The second /e starts with $foo and replaces it with its value. $foo, then, turns into 'Fred', and that's finally what's left in the string:
$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'
The /e will also silently ignore violations of strict, replacing undefined variable names with the empty string. Since I'm using the /e flag (twice even!), I have all of the same security problems I have with eval in its string form. If there's something odd in $foo, perhaps something like #{[ system "rm -rf /" ]}, then I could get myself in trouble.
To get around the security problem, I could also pull the values from a hash instead of evaluating variable names. Using a single /e, I can check the hash to ensure the value exists, and if it doesn't, I can replace the missing value with a marker, in this case ??? to signal that I missed something:
my $string = 'This has $foo and $bar';
my %Replacements = (
foo => 'Fred',
);
# $string =~ s/\$(\w+)/$Replacements{$1}/g;
$string =~ s/\$(\w+)/
exists $Replacements{$1} ? $Replacements{$1} : '???'
/eg;
print $string;
Well, I just tried below workaround it worked. Please have a look
my $str1 = "1234\n\t5678";
print $str1;
#it prints
#1234
# 5678
$str1 =~ s/\t/\\t/g;
$str1 =~ s/\n/\\n/g;
print $str1;
#it prints exactly the same
#1234\n\t5678