Perl String comparison - string

I'm trying to compare a string to another.
If it's a JSON structure which contains things, I want to print "contains things".
If it's a JSON structure which doesn't contain thing, I print "empty"
If it something which is not between curly brackets "{}", i print that there's an error.
Here's what I've done :
if($content =~ m/{.+}/){
print "Contains things \n";
} elsif($content eq "{}"){
$job_status{$url}="";
print "empty \n";
} else {
print "Error \n";
}
When I pass "{}" to the variable $content, he does not enter the "elsif", but go to the "else", and throw an error.
I've tried to put "==" instead the "eq" in the if, even though I know it's for numbers. When so, he enters the "elsif", and print "empty", like he should do with the "eq", and throws :
Argument "{}" isn't numeric in numeric eq (==)".
I could use the JSON library but I prefer not.
Thanks for your help !
Bidy

It works for me. Does $content have a newline character? Try chomp $content;.
use warnings;
use strict;
my $content = '{}';
if($content =~ m/{.+}/){
print "Contains things \n";
} elsif($content eq "{}"){
print "empty \n";
} else {
print "Error \n";
}
__END__
empty

I can replicate the behaviour if I add a newline after the {}:
#!/usr/bin/perl
use strict;
use warnings;
my $content = "{}\n";
if($content =~ m/{.+}/){
print "Contains things \n";
} elsif($content eq "{}"){
print "empty \n";
} else {
print "Error \n";
}
It returns "Error", if I replace eq with ==, it returns empty, because both "{}" and "{}\n" are numerically 0. A warning is thrown as you mentioned.
You might try to chomp the $content before processing it.

A top-level JSON thingy can be an object ({...}) or an array ([...]), but you're only checking for one of those. If you merely want to see if it's empty, I'd check the length of the string:
chomp $possible_json;
if( $length $possible_json >= 3 ) { ... }
You might also consider Randal Schwartz's regex for JSON parsing. It doesn't handle everything, but it's often enough for simple things.

I'd probably end up breaking it up:
unless ($content) {print "Error\n"};
$content =~ /{(.*)}/
my $resp = $1;
if ($resp) {
print "Contains Things ($resp)\n";
} else {
print "Empty\n";
}

Related

How can I get if .. else to work?

I wrote a Perl program where the user should type in a user name. If they enter admin, they should see the message
Welcome, admin!
Otherwise the console output should be
The username is incorrect
Here is my code
use utf8;
print "Username: ";
$username = <STDIN>;
if ( $username eq "admin" ) {
print "Welcome, admin!";
}
else {
print "The username is incorrect.";
}
But whatever the user inputs the program goes on to the else branch.
Why does this happen?
Whenever you are not sure why a comparison fails, make sure you know what's in your variable:
use Data::Dumper;
local $Data::Dumper::Useqq = 1;
print Dumper $variable;
# print Dumper \#array;
# print Dumper \%hash;
like #ikegami suggested, you need to use chomp:
chomp $username;
perldoc -f chomp
The empty <> operator is usually the best choice for input. It will read data from any files named on the command line, or from the keyboard if there were none
Your $username = <STDIN> will read from the keyboard, and if you enter admin and the enter key it will contain "admin\n". So you need to chomp the LF character from the end of the input
You should also use strict and use warnings 'all' at the start of every Perl program
Like this
use strict;
use warnings 'all';
print "Username: ";
my $user_name = <>;
chomp $user_name;
if ( $user_name eq 'admin' ) {
print "Welcome, admin!\n";
}
else {
print "The username is incorrect\n";
}
The comparison never succeed because you don't remove the line feed created by pressing Enter. Use chomp!
As everyone else already mentioned, you have a line feed and chomp will sort that out. In the rare event however where a user perhaps types a space before admin, it will still fail. You can therefore use left and right trim
use strict;
use warnings 'all';
print "Username: ";
my $user_name = <>;
$user_name =~ s/^\s+|\s+$//g;
if ( $user_name eq 'admin' ) {
print "Welcome, admin!\n";
}
else {
print "The username is incorrect\n";
}
which will match admin followed by newline, space or tab before and space or tab after admin.
You are missing to use chomp. When user has entered admin, it translated to admin\n, so we need to remove that \n. chomp is used to remove the $/ variable (line feed character) which is set to mostly \n (new line). $/ is the input record separator, newline by default.
use utf8;
print "Username: ";
$username = <STDIN>;
chomp $username;
if ( $username eq "admin" ) {
print "Welcome, admin!";
}
else {
print "The username is incorrect.";
}

parsing conditional operators as strings and using as conditional operators

my $line ="Corner:Default,Output:fall_delay_slew_1,Mean=34.97p,Std- dev=1.767p,Min=30.02p,Max=39.71p"; #added semicolon
my $my_value="COND = Mean > 3"; #this has come from the parsed file.
$my_value =~ m/(\w+)\s*(.)\s*(\d+)/;
my $cond=$1;
my $sign=$2;
my $value=$3;
print "DEBUG:cond is $cond and sign $sign and value $value \n";
if ( $line =~ m/$cond=(.*?),/) {
if ( "$value $sign $1" ) {
print "$value is $sign than $1\n";
} else {
print "actual value is less\n";
}
}
If you see in the above if statement always evaluates to true.
How can I solve this kind of problem i.e $sign = "<" (could be any operator)
but when I want to compare it with $value I want it to function as an
operator and not as a string.
What you're willing to do (executing a string as code) can be done with
eval. That doesn't mean it is the most appropriate way of doing
it though. Do it only if you guarantee your input safety and check for
it.
A better way would be checking the operator your self and determining
how to proceed. If you use a recent Perl version, the given-when
feature can be handy to do this:
use feature 'switch'; # not needed if you already use 5.010 or greater
given ($sign) {
when ('<') { say "$cond less than $value" }
when ('>') { say "$cond greater than $value" }
default {
warn "unrecognized operator `$sign'\n";
# decide what to do
}
}

How to read "<somestring>" in input string in perl

Below is my code. It still produces same string with no "<init>"
input string :
1: invokespecial #1 // Method java/lang/Object."<init>":()V
my $file = "Hello.javap";
open my $fh, '<', $file or die "Could not open '$file' $!";
while (my $line = <$fh>) {
if (index(uc($line), uc("Code:")) != -1) {
$code_block_started=1;
}
if(index($line,":")==-1)
{
if (my ($method) = $line =~ /.* \/\/ Method (.*);/) {
print "Method: $method\n";
}
print $line;
$code_block_started=0;
}
if($code_block_started){
if ($line =~/[0-9]/) {
my #num_strip = split(':',$line);
my #get_command = split(' ',$num_strip[1]);
# print "\n $get_command[0]";
$count{$get_command[0]}++;
}
}
Are you simply asking how to escape the " in perl? If so, write \"<init>\" just like in most languages.
Are you asking for a regular expression? If so, $str ~= /.* \/\/ Method (.*);/ will put java/lang/Object."<init>":()V into $1.
while (my $str = <>) {
if (my ($method) = $str =~ m{// Method (.*)}) {
print "$method\n";
}
}
when Perl sees the double-quote just before the word "name" it thinks that was the end of the string and then it complains about the word name being a bareword.
You might have already guessed, we need to escape the embedded " character:
use strict;
use warnings;
my $name = 'foo';
print "The \"name\" is \"$name\"\n";
http://perlmaven.com/quoted-interpolated-and-escaped-strings-in-perl

Get rid of warning in perl number adder code

I am writing a program that takes numbers from the command line until the user enters a blank line.
Should the user enter something that is neither newline nor numeric, it notifies the user, and continues.
While everything works, I have use warnings turned on, and it doesn't seem to like the second if conditional if the enters something invalid.
Argument "foo" isn't numeric in numeric eq (==) at adder.pl line 25, <STDIN> line 4.
I don't like running the program with this warning. How can I improve my code?
This is my program
#!/usr/bin/perl
use strict;
use warnings;
#declare variable
my $number = 0; #final answer
my $input;
#prompt the user
print "Input some integers, line by line. When you are done, press return to add them up." . "\n";
while (1) {
#get input from user
$input = <STDIN>;
#remove newlines
chomp($input);
#user pnches in newline
if ($input eq '') { #if the answer is new line
#quit the loop
last;
} #end of if statement
#user punches in bad input
elsif ($input == 0 && $input ne '0' && $input ne '') {
#tell the user what happened and how to rectify it
print "Input must be an integer." . "\n";
} # end of elsif statement
else {
chomp($input);
$number += $input;
} # end of else statement
} #end of while
print "Total is: $number\n";
Perl does DWIM very well. It is famous for it.
So, whatever language you have come from - it looks like C - forget about checking for both strings and numbers: a Perl scalar variable is whatever you ask it to be.
That means something like
elsif ($input == 0 && $input ne '0' && $input ne '') {
makes little sense. Anything read from the keyboard is initially a string, but it will be a number if you want. You are asking for $input to evaluate as zero but not to be the literal string 0. That applies to very few strings, for instance 00 or 0e0.
I think this is what you meant to write. Please take a look.
Isn't it clearer without comments?
use strict;
use warnings;
print "Input some integers line by line. When you are done, press return to add them up\n";
my $total = 0;
while (<>) {
chomp;
last unless /\S/;
if (/\D/) {
print "Input must be an integer\n";
next;
}
$total += $_;
}
print "Total is: $total\n";
Since Perl is untyped, and you are using $input as both a number and a string, you get that warning because "foo" isn't a number and "==" is used to compare equality of numbers.
You first need to check to see if $input is a number or not. One suggestion:
if ($input =~ /^\d+$/)
{
$number += $input;
}
else
{
print "Input must be an integer.\n";
}

Perl: adding a string to $_ is producing strange results

I wrote a super simple script:
#!/usr/bin/perl -w
use strict;
open (F, "<ids.txt") || die "fail: $!\n";
my #ids = <F>;
foreach my $string (#ids) {
chomp($string);
print "$string\n";
}
close F;
This is producing an expected output of all the contents of ids.txt:
hello
world
these
annoying
sourcecode
lines
Now I want to add a file-extension: .txt for every line. This line should do the trick:
#!/usr/bin/perl -w
use strict;
open (F, "<ids.txt") || die "fail: $!\n";
my #ids = <F>;
foreach my $string (#ids) {
chomp($string);
$string .= ".txt";
print "$string\n";
}
close F;
But the result is as follows:
.txto
.txtd
.txte
.txtying
.txtcecode
Instead of appending ".txt" to my lines, the first 4 letters of my string will be replaced by ".txt" Since I want to check if some files exist, I need the full filename with extension.
I have tried to chop, chomp, to substitute (s/\n//), joins and whatever. But the result is still a replacement instead of an append.
Where is the mistake?
Chomp does not remove BOTH \r and \n if the file has DOS line endings and you are running on Linux/Unix.
What you are seeing is actually the original string, a carriage return, and the extension, which overwrites the first 4 characters on the display.
If the incoming file has DOS/Windows line endings you must remove both:
s/\R+$//
A useful debugging technique when you are not quite sure why your data is getting set to what it is is to dump it with Data::Dumper:
#!/usr/bin/perl -w
use strict;
use Data::Dumper ();
$Data::Dumper::Useqq = 1; # important to be able to actually see differences in whitespace, etc
open (F, "<ids.txt") || die "fail: $!\n";
my #ids = <F>;
foreach my $string (#ids) {
chomp($string);
print "$string\n";
print Data::Dumper::Dumper( { 'string' => $string } );
}
close F;
have you tried this?
foreach my $string (#ids) {
chomp($string);
print $string.".txt\n";
}
I'm not sure what's wrong with your code though. these results are strange

Resources