how to substitute actual value of variable in a file which is present in another file in perl - perl

I have two file.Variables are declared in first file($one=1;) , in second file variable name is given ($one). I want to substitute this variable name with actual value and print the output.
File1.txt
variables are gieven here
$one=1;
$name="gorge";
$animal="cat";
File2.txt
This number is x=$one/or less then two
his name is $name
It is a $animal/ kind of animal.
Expected output
This number is x=1/or less then two
his name is gorge
It is a cat/ kind of animal.
I tried with this code:
open (data1,"</home/file1");
open (data2,"</home/file2");
while (<data1>){
while (<data2>){
print $_;
}
}
close data2;
close data1;
Thank You.

You need a templating system
One of the most popular ones is Template Toolkit
For example, with this template file
File2.template
This number is x=[% one %]/or less then two
his name is [% name %]
It is a [% animal %]/kind of animal.
And this Perl code
main.pl
use strict;
use warnings 'all';
use Template;
my $tt = Template->new;
my $vars = {
one => 1,
name => 'gorge',
animal => 'cat',
};
$tt->process('File2.template', $vars);
The result is this
output
This number is x=1/or less then two
his name is gorge
It is a cat/kind of animal.

I think you're fishing for something that is a horribly bad idea.
So I'll suggest a different approach, of building regular expressions to replace the text. In doing this though - the use of $one is going to be a bit confusing, because that means a scalar variable in perl, and this is "just" going to be a pattern match.
So if you can change that - you should:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my %replace = ( 'one' => '1',
'name' => 'gorge',
'animal' => 'cat' );
my $search = join ( '|', keys %replace );
$search = qr/\$($search)/;
print Dumper \%replace;
print $search;
while ( <DATA> ) {
s/$search/$replace{$1}/g;
print;
}
__DATA__
This number is x=$one/or less then two
his name is $name
It is a $animal/ kind of animal.
You can build your replace patterns something like this:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my %replace = map { m/\$(\w+)=\"?([^;\"]+)/ } <DATA>;
print Dumper \%replace;
__DATA__
$one=1;
$name="gorge";
$animal="cat";
This gives you:
$VAR1 = {
'name' => 'gorge',
'one' => '1',
'animal' => 'cat'
};

If you're going to be any kind of Perl programmer, then you'll need to read the Perl FAQ.
In there, you'll find an answer to your question.
How can I expand variables in a text string?
If you read that answer, you'll end up with code very similar to what Sobrique gave you. However, in order to get to that code, you'll need to first pass the first paragraph in the answer which says:
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.
That's really good advice. You should follow it.

Related

Perl dereference on args cannot be used in comparison, but copy of it can

I have read some arguments at the command line:
#!/usr/bin/env perl
use 5.0360;
use warnings FATAL => 'all';
use autodie ':default';
use Devel::Confess 'color';
use Getopt::ArgParse;
my $parser = Getopt::ArgParse->new_parser(
help => 'This script finds and pretty-prints a line within a CSV file',
);
$parser-> add_args(
['-file', '-f', required => 1, type => 'Scalar'],
['-regex', '-r', required => 1, type => 'Scalar'], # regex pattern within each line
['-sep' , '-s', required => 0, type => 'Scalar']
);
my $args = $parser->parse_args(#ARGV);
my $sep = $args->sep // ',';
my $regex = $args->regex;
my #header;
say $args->regex;
open my $fh, '<', $args->file;
while (<$fh>) {
chomp;
if ($. == 1) {
#header = split $sep;
next
}
next unless /$regex/; # key point
say __LINE__;
# code later
}
the problem here is that the regex comparison
next unless /$regex/
works, but
next unless /$args->regex/
does not work, even though the two are copies of each other via my $regex = $args->regex;
Strangely, I can use $args->file but cannot use $args->regex
Why does $args->regex work like this? What is the correct terminology for $args->regex? It's not a hash, it's some sort of object.
You can't interpolate method calls into a string. I guarantee you that $args->file doesn't work either here. Note that $args->regex is not a field access but a method call, equivalent to $args->regex().
When interpolating a variable into a quote-like context (including regexes), you can use scalars, arrays, and array/hash field accesses.
I think that using a named variable my $regex = $args->regex is the clearest solution here. But if you really want to interpolate arbitrary expressions into a string, you can use a trick: you can interpolate arrays #foo, thus also an array dereference #{ ... }. Then:
next unless /#{[ $args->regex ]}/;

How to convert string to floating point number inside a Perl hash?

My motive is to convert the string number into floating point number while creating a hash.
I have placed my entire code and error below. Please help me to solve this issue.
Sample code
use strict;
use warnings;
use Data::Dumper;
my $price = 8.5;
my $g={};
$g->{'get'}=sprintf('%.02f',$price);
print Dumper($g);
Current output
$VAR1 = {
'get' => '8.50'
};
Expected output
$VAR1 = {
'get' => 8.50
};
Despite the single quotes around 8.50 in the Dumper output, Perl will still treat it as a numeric value when you go to use it:
use strict;
use warnings;
my $price = 8.5;
my $g={};
$g->{'get'}=sprintf('%.02f',$price);
my $x = 5;
printf "%.02f\n", $x + $g->{get};
Outputs:
13.50
use Scalar::Util 'looks_like_number';
.
.
print Dumper($g) =~ s/'(.*?)'/looks_like_number($1)?$1:"'$1'"/ger;
Which changes the output from Dumper before it's printed. It removes both 's of every single quoted string if it looks like a number according to Scalar::Util.
I suspect you're worrying unnecessarily here. Perl treats strings and numbers as largely interchangeable and will generally do the right thing with data of either type. The number of times when you should care if you have a string or a number is tiny.
In fact, even if you explicitly give Perl a number in code like yours, it will be displayed as a string:
$ perl -MData::Dumper -E'say Dumper { get => 8.5 }'
$VAR1 = {
'get' => '8.5'
};

How do you treat hashes in arrays properly?

I've got an array of hashes:
my #questions = (
{"Why do you study here?" => "bla"},
{"What are your hobbies?" => "blabla"});
And I try to loop through it:
foreach (#questions) {
my $key = (keys $_)[0];
$content .= "\\section{$key}\n\n$_{$key}\n\n";
}
giving me
Use of uninitialized value in concatenation (.) or string at
convert.pl line 44.
Where does the error come from?
$_{$key} looks up $key in the hash variable %_. The sigil $ at the beginning indicates that the type of the result is a scalar. It's the syntactic construct VAR{KEY} that determines that VAR must be a hash. Although $_ and %_ use the same symbol as a name, the different sigils make them unrelated variables.
You need to dereference the hash reference $_ into the underlying hash. The syntax for this is $_->{$key} or ${$_}{$key}.
See the reference tutorial for a more general presentation of the topic.
Gilles already explained how to use your current data structure, but I would recommend that you use a different data structure altogether: a simple hash.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my %answers = (
"Why do you study here?" => "bla",
"What are your hobbies?" => "blabla"
);
while (my ($question, $answer) = each %answers) {
say "Question: $question";
say "Answer: $answer";
}
Output:
Question: Why do you study here?
Answer: bla
Question: What are your hobbies?
Answer: blabla
I find this easier to work with than an array of hashes, each of which only contains a single key/value pair.
If you want to iterate through the hash in a certain (non-sorted) order, there are a couple of options. The simplistic solution is to maintain an array of keys in the order you want to access them:
# In the order you want to access them
my #questions = ("What are your hobbies?", "Why do you study here?");
my %answers;
#answers{#questions} = ("blabla", "bla");
foreach my $question (#questions) {
say "Question: $question";
say "Answer: $answers{$question}";
}
Output:
Question: What are your hobbies?
Answer: blabla
Question: Why do you study here?
Answer: bla
Another option is to use Tie::IxHash (or the faster XS module Tie::Hash::Indexed) to access keys in insertion order:
use Tie::IxHash;
tie my %answers, "Tie::IxHash";
%answers = (
"Why do you study here?" => "bla",
"What are your hobbies?" => "blabla"
);
while (my ($question, $answer) = each %answers) {
say "Question: $question";
say "Answer: $answer";
}
Output:
Question: Why do you study here?
Answer: bla
Question: What are your hobbies?
Answer: blabla
The elements of #questions are references to hash, not hashes. Therefore, you should use them like this:
foreach (#questions) {
my $key = (keys %$_)[0];
print "\\section{$key}\n\n$_->{$key}\n\n";
}
See perlref for how to create and use reference.

Using # and $ with the same variable name in Perl

I am declaring the same variable name with # and $:
#ask=(1..9);
$ask="insanity";
print ("Array #ask\n");
print ("Scalar $ask\n");
Without using use strict I am getting output correctly but when I am using use strict it gives me a compilation error.
Do these two variables refer to two different memory locations or is it the same variable?
You've got two variables:
#ask
$ask
You could have %ask (a hash) too if you wanted. Then you'd write:
print $ask, $ask[0], $ask{0};
to reference the scalar, the array and the hash.
Generally, you should avoid this treatment, but the variables are all quite distinct and Perl won't be confused.
The only reason use strict; is complaining is because you don't prefix your variables with my:
#!/usr/bin/env perl
use strict;
use warnings;
my #ask = (1..9);
my $ask = "insanity";
my %ask = ( 0 => 'infinity', infinity => 0 );
print "Array #ask\n";
print "Scalar $ask\n";
print "Hash $ask{0}\n";
with use strict; you need to declare your variables first before using it.
For example:
use strict;
my #ask=(1..9);
my $ask="insanity";
print ("Array #ask\n");
print ("Scalar $ask\n");
#ask and $ask are different variables — as is %ask — and it is not an error to do this. It is however poor style.
Because the sigil changes when you use them, such as when you use $ask[1] to get the second element of #ask, the code becomes harder to read and use strict will also not be able to tell if you've gotten confused. Thus it's a good idea to use names that differ in more than the sigil unless you know what you're doing. So you could use e.g. #asks and $ask.
The error you are getting with strict is not due to variable names. It is because you are not declaring the variables (using one of my, our, local, or state. Nor are you using the vars pragma.
Short answer: Stick a my in front of each variable, and you'll be strict-compliant.
For package variables, you can examine entries in the symbol table. $ask and #ask are separate entities:
#!/usr/bin/env perl
use Devel::Symdump;
use YAML;
#ask=(1..9);
$ask="insanity";
my $st = Devel::Symdump->new('main');
print Dump [ $st->$_ ] for qw(
scalars
arrays
);
Among other things, this code will output:
--
…
- main::ask
…
---
…
- main::ask
…
Being able to use the same name can help when, say, you have an array of fish and you are doing something with each fish in the array:
for my $fish (#fish) {
go($fish);
}
Normally, it is more expressive to use the plural form for arrays and hashes, the singular form for elements of an array, and something based on the singular form for keys in a hash:
#!/usr/bin/env perl
use strict;
use warnings;
my #ships = ('Titanic', 'Costa Concordia');
my %ships = (
'Titanic' => {
maiden_voyage => '10 April 1912',
capacity => 3_327,
},
'Costa Concordia' => {
maiden_voyage => '14 July 2006',
capacity => 4_880,
},
);
for my $ship (#ships) {
print "$ship\n";
}
while (my ($ship_name, $ship_details) = each %ships) {
print "$ship_name capacity: $ship_details->{capacity}\n";
}

How do I create and access a Perl hash with scalar keys whose values are arrays?

In Perl 5.10, how do I create and access a hash with scalar keys whose values are arrays?
#Doing this does not work properly.
%someHash= ("0xfff" => ('Blue', 'Red', 'Yellow'));
#arr = #fileContents{"0xfff"};
print #arr;
When I print the array, the only thing that prints is "ARRAY('randmemAddr')". When I do a foreach loop on #arr, only the first element is printed. I have then concluded that I have not stored the array properly in the hash.
My original answer posted working code, but didn't really explain the problem with yours. This is expanded a bit to correct that. Your example had two problems. First, you had a problem when making the reference. You need to use [ ] instead of the standard parentheses in order to create a reference (to an anonymous array). Second, when you tried to get at the reference, you left off one set of brackets. You want to put the reference itself inside #{ } in order to get at the whole array. (Also, and this may be a typo: you have no $ before filecontents.)
The code here is essentially from perldoc perldsc. I highly recommend it. Also very useful if you're new to references in Perl is perldoc perlreftut. Both tutorials discuss how to make and get at references in a variety of situations. Finally, you can find a good cheat sheet for references in a post on PerlMonks.
#!/usr/bin/env perl
use strict;
use warnings;
my %HoA = (
flinstones => [ qw/fred barney/ ],
jetsons => [ qw/george jane elroy/ ],
);
for my $family (keys %HoA) {
print "Members of the \u$family:\n";
print "\t #{ $HoA{$family} }\n";
}
You need to be more explicit about storing a reference to an array and then dereferencing it.
Try this:
#Doing this doeswork properly.
%someHash= ("0xfff" => ['Blue', 'Red', 'Yellow']);
#arr = #{$fileContents{"0xfff"}};
print #arr;
notice the parens turned to brackets and the cast when using it.
I find it much easier to use Data::Dumper module. Odds are very high that it comes with your perl distribution. It allows you to quickly see what your data structure is.
In your case it would be:
use Data::Dumper;
my %someHash= ("0xfff" => ('Blue', 'Red', 'Yellow'));
print Dumper \%someHash;
This will output:
$VAR1 = {
'Red' => 'Yellow',
'0xfff' => 'Blue'
};
of course, to fix it you need to store your array as reference:
use Data::Dumper;
my %someHash= ("0xfff" => [qw(Blue Red Yellow)]);
print Dumper \%someHash;
Which will produce:
$VAR1 = {
'0xfff' => [
'Blue',
'Red',
'Yellow'
]
};
Bottom line is Data::Dumper is your best friend
Hash or array elements are always scalars (except in certain internal uses, not directly possible from Perl), so you can store a reference to an array but not an array.