Compilation Error: Requires Explicit Package Name - perl

I am just starting out with Perl and I am writing a program that reads a file and puts the morse code from that file into plain text in another file. I am getting this error and I cannot figure out what is wrong. Any help is appreciated!
Error I am receiving:
Jessicas-MacBook-Pro:Documents jessica$ perl -w Morse_to_Text.pl <Morse3.rtf> MorseTest.txt
Global symbol "$message" requires explicit package name at Morse_to_Text.pl line 20.
Global symbol "$message" requires explicit package name at Morse_to_Text.pl line 26.
Global symbol "$message" requires explicit package name at Morse_to_Text.pl line 26.
Global symbol "$message" requires explicit package name at Morse_to_Text.pl line 27.
Code:
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
my %morsecode=(
".-" =>"A", "-..." => "B", "-.-." => "C", "-.." => "D", "." => "E",
"..-." => "F", "--." => "G", "...." => "H", ".." => "I", ".---" => "J",
"-.-" => "K", ".-.." => "L", "--" => "M", "-." => "N", "---" => "O",
".--." => "P", "--.-" => "Q", ".-." => "R", "..." => "S", "-" => "T",
"..-" => "U", "...-" => "V", ".--" => "W", "-..-" => "X", "-.--" => "Y",
"--.." => "Z", "-----" => "0", ".----" => "1", "..---" => "2", "...--" => "3",
"....-" => "4", "....." => "5", "-...." => "6", "--..." => "7", "---.." => "8",
"----." => "9", ".-.-.-" => ".", "--..--" => ",", "..--.." => "?", ".----." => "'",
"-....-" => "-", ".-..-." => '"', ".--.-." => "#", "-...-" => "=", "!" => " "
);
while (<>) {
chomp;
foreach my $char ( split ' ' ) {
$message = $morsecode{$char} + $message;
print $message;
};
}

You use strict, so you should declare the global variable $message first. But as ikegami said in comment, use strict and warnings are one of the best practices when writing perl code. The pragmas catch many errors sooner that they would be caught otherwise, which makes it easier to find the root causes of the errors (just like the error you provide). The root cause might be the need for an error or validation check, and that can happen regardless or programmer skill.
I think what you want is the following code:
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
my %morsecode=(
".-" =>"A", "-..." => "B", "-.-." => "C", "-.." => "D", "." => "E",
"..-." => "F", "--." => "G", "...." => "H", ".." => "I", ".---" => "J",
"-.-" => "K", ".-.." => "L", "--" => "M", "-." => "N", "---" => "O",
".--." => "P", "--.-" => "Q", ".-." => "R", "..." => "S", "-" => "T",
"..-" => "U", "...-" => "V", ".--" => "W", "-..-" => "X", "-.--" => "Y",
"--.." => "Z", "-----" => "0", ".----" => "1", "..---" => "2", "...--" => "3",
"....-" => "4", "....." => "5", "-...." => "6", "--..." => "7", "---.." => "8",
"----." => "9", ".-.-.-" => ".", "--..--" => ",", "..--.." => "?", ".----." => "'",
"-....-" => "-", ".-..-." => '"', ".--.-." => "#", "-...-" => "=", "!" => " "
);
my $message;
while (<>) {
chomp;
foreach my $char ( split ' ' ) {
$message = $message.$morsecode{$char};
};
}
print $message."\n";

It means you didn't declare $message using my $message; where appropriate.
You might benefit from running your script using
perl -Mdiagnostics script.pl
It'll explain many warnings/errors.

Related

Printing content of hash of arrays of arrays

I've been trying to read the following structure in Perl:
my %Homes = (
"Home 1" => [
'TYPE_OF_HOUSE' => "Villa",
'FIELD1' => ["1","2","3"],
'Field2' => ["2","3","4"],
'Field3' => ["3","4","5"],
],
"Home 2" => [
'TYPE_OF_HOUSE' => "Duplex",
'FIELD1' => ["1","2","3"],
'Field2' => ["2","3","4"],
'Field3' => ["3","4","5"],
],
"Home 3" => [
'TYPE_OF_HOUSE' => "Apartment",
'FIELD1' => ["1","2","3"],
'Field2' => ["2","3","4"],
'Field3' => ["3","4","5"],
],
);
By using the following:
my #data_Array;
my ($inner_Key,$key,$names_ref);
foreach $key (keys %Homes)
{
print("Inner values of house $key are:");
foreach $inner_Key ( #{$Homes{$key}})
{
if ($inner_Key != "TYPE_OF_HOUSE")
{
$names_ref = \#$inner_Key;
#data_Array = #{$names_ref};
print($data_Array[0]);
print($data_Array[1]);
print($data_Array[2]);
}
else
{
print($inner_Key);
}
}
}
I successfully printed the: "Home 1", "Home 2", but when trying to read the inner content, even though I used reference to an array, it didn't go well. What did I miss? My goal was to "identify" the type of field, and if it was TYPE_OF_HOUSE, then simply print it because it is not an array. Otherwise, print the inner content of its array.
You must use strict and warnings because they will tell you a lot about what is wrong with your code.
You need to use ne instead of != when comparing strings.
You should use a different data structure to make it simpler to access inner data elements. You have a hash-of-arrays, but it would make more sense as a hash-of-hashes. By using => for 'TYPE_OF_HOUSE' => "Villa", you've tricked yourself into believing that is a hash. However, it is just a flat array. The 1st element of the array is TYPE_OF_HOUSE, the 2nd element is Villa, the 3rd is FIELD1, the 4th is an array ref, etc.
use warnings;
use strict;
my %Homes = (
"Home 1" => {
'TYPE_OF_HOUSE' => "Villa",
'FIELD1' => [ "1", "2", "3" ],
'Field2' => [ "2", "3", "4" ],
'Field3' => [ "3", "4", "5" ],
},
"Home 2" => {
'TYPE_OF_HOUSE' => "Duplex",
'FIELD1' => [ "1", "2", "3" ],
'Field2' => [ "2", "3", "4" ],
'Field3' => [ "3", "4", "5" ],
},
"Home 3" => {
'TYPE_OF_HOUSE' => "Apartment",
'FIELD1' => [ "1", "2", "3" ],
'Field2' => [ "2", "3", "4" ],
'Field3' => [ "3", "4", "5" ],
},
);
my #data_Array;
my ( $inner_Key, $key, $names_ref );
foreach $key ( keys %Homes ) {
print("Inner values of house $key are:");
print "\n";
foreach $inner_Key ( keys %{ $Homes{$key} } ) {
if ( $inner_Key ne "TYPE_OF_HOUSE" ) {
#data_Array = #{ $Homes{$key}{$inner_Key} };
print( $data_Array[0] );
print "\n";
print( $data_Array[1] );
print "\n";
print( $data_Array[2] );
print "\n";
}
else {
print($inner_Key);
print "\n";
}
}
}
I used perltidy to improve the indentation. I added newlines to make your print output easier to read.

How to recreate perl's array of hashes in golang?

In perl I can push $hashref into #array and have this data for next foreach and possible encode_json (HTTP POST).
I can't figure out how to recreate the same login in golang?
$VAR1 = [
{
'address' => 'test.com',
'id' => 101,
'hostgroups' => [
zero
'one',
'or many'
],
'host_name' => 'test.com',
'alias' => 'test.com',
'template' => 'generic',
'file_id' => 'etc/config'
},
{
'address' => 'test2.com',
'id' => 102,
'hostgroups' => [
zero
'one',
'or many'
],
'host_name' => 'test2.com',
'alias' => 'test2.com',
'template' => 'generic',
'file_id' => 'etc/config'
},
(..)
var array = []map[string]interface{}{
{"address": "test.com", "hostgroups": []string{"zero", "one", "or many"}, "id": 101},
{"address": "test2.com", "hostgroups": []string{"zero", "one", "or many"}, "id": 102},
}
This is the answer.
type host map[string]interface{}
var hosts []host
h := host{
"id": id,
"file_id": "etc/config/hosts.cfg",
"host_name": host_name,
"alias": host_name,
"address": host_name,
"hostgroups": hg,
"template": "generic-host",
}
hosts = append(hosts, h)

How do I use map to merge an array of hashes?

Hoping someone could explain the proper process for this. I have a data structure like this:
[
{
Author => "101",
WK1 => "",
WK10 => "",
WK11 => "",
WK12 => "",
WK13 => "",
WK14 => "X",
WK15 => "",
},
{
Author => "102",
WK1 => "",
WK10 => "",
WK11 => "",
WK12 => "X",
WK13 => "X",
WK14 => "",
WK15 => "",
WK2 => "X",
WK3 => "X",
WK4 => "",
},
{
Author => "101",
WK1 => "",
WK10 => "",
WK11 => "",
WK12 => "",
WK13 => "",
WK14 => "X",
WK15 => "X",
},
]
WK keys may or may not exist. The Author key will always exist, and I’m trying to merge those duplicates. Overwriting values is ok (if defined).
Should I try map (not sure how), or would it be better to create a new hash using the Author as key, pushing the other values into an array? Something like
foreach $x (#$data) {
%new_hash = ...
...
}
scratching head
It sounds like you are starting with something like the following:
my $records = [
{ Author => "101", WK1 => "", WK2 => "X", WK3 => "X" },
{ Author => "101", WK1 => "X", WK2 => "", WK4 => "X" },
{ Author => "102", WK1 => "", WK2 => "", WK3 => "X" },
];
It sounds like you want to produce the following:
my $records_by_author = (
"101" => { Author => "101", WK1 => "X", WK2 => "", WK3 => "X", WK4 => "X" },
"102" => { Author => "102", WK1 => "", WK2 => "", WK3 => "X" },
);
The following will do that:
my %records_by_author;
for my $record (#$records) {
my $author = $record->{Author};
$records_by_author{$author} = {
( $records_by_author{$author} ? %{ $records_by_author{$author} } : () ),
%$record,
};
}
If instead you want the following output:
my $records = [
{ Author => "101", WK1 => "X", WK2 => "", WK3 => "X", WK4 => "X" },
{ Author => "102", WK1 => "", WK2 => "", WK3 => "X" },
];
Just add the following:
$records = [ values(%records_by_author) ];
It you want this output and you want to preserve the original order, let me know.
I suggest merging along the lines of the code below. From each anonymous hash in #$data, grab the author identifier and then update the merged WK values where we never overwrite a non-empty string with an empty one.
You could do the same with map, and that would be a worthwhile exercise. It seems to read much more naturally as nested structural loops.
my %authorwk;
for (my $i = 0; #$data; ++$i) {
local $_ = shift #$data;
die "$0: missing Author in record $i" unless exists $_->{Author};
my $author = $_->{Author};
while (my($wk,$present) = each %$_) {
next unless $wk =~ /^WK/;
$authorwk{$author}{$wk} = $present
if $present || !exists $authorwk{$author}{$wk};
}
}
map is inappropriate here: a series of slice assignments is all that is necessary
It looks like this. Note that the only duplicate author 101 has an identical set of keys in both instances, so I've added key WK7 to the first instance and WK8 to the second so that you can see that they are both added to the result
use strict;
use warnings 'all';
my $data = [
{
Author => 101,
WK7 => "7", WK1 => "", WK10 => "", WK11 => "",
WK12 => "", WK13 => "", WK14 => "X", WK15 => "",
},
{
Author => 102,
WK1 => "", WK10 => "", WK11 => "", WK12 => "X",
WK13 => "X", WK14 => "", WK15 => "", WK2 => "X",
WK3 => "X", WK4 => "",
},
{
Author => 101,
WK8 => "8", WK1 => "", WK10 => "", WK11 => "",
WK12 => "", WK13 => "", WK14 => "X", WK15 => "X",
},
];
my %authors;
for my $item ( #$data ) {
my $author = $item->{Author};
#{ $authors{$author} }{keys %$item} = values %$item;
}
use Data::Dump;
dd \%authors;
output
{
101 => {
Author => 101,
WK1 => "",
WK10 => "",
WK11 => "",
WK12 => "",
WK13 => "",
WK14 => "X",
WK15 => "X",
WK7 => 7,
WK8 => 8,
},
102 => {
Author => 102,
WK1 => "",
WK10 => "",
WK11 => "",
WK12 => "X",
WK13 => "X",
WK14 => "",
WK15 => "",
WK2 => "X",
WK3 => "X",
WK4 => "",
},
}

Perl - Error caused by uninitialized value in print

I am writing a simple program that reads morse code from a file and converts it to plain text. I am getting some crazy errors though. I am not very familiar with perl and I am having to run it from command line. Below is the error that I am receiving and the code. It is possible that I am just running it wrong. I am typing: "perl -w Lott_Morse.pl morse.txt" into the command line. Any help would be appreciated.
Error:
Use of uninitialized value in print at Lott_CSC360_Morse2.pl line 31, <> line 7.
Use of uninitialized value in print at Lott_CSC360_Morse2.pl line 31, <> line 7.
Use of uninitialized value in print at Lott_CSC360_Morse2.pl line 31, <> line 7.
Use of uninitialized value in print at Lott_CSC360_Morse2.pl line 31, <> line 7.
Use of uninitialized value in print at Lott_CSC360_Morse2.pl line 31, <> line 7.
Use of uninitialized value in print at Lott_CSC360_Morse2.pl line 31, <> line 7.
The message is 0Jessicas-MacBook-Pro:Documents
Code:
#!/usr/bin/perl
use 5.010;
use warnings;
%morse_to_plain=(
".-" =>"A", "-..." => "B", "-.-." => "C", "-.." => "D", "." => "E",
"..-." => "F", "--." => "G", "...." => "H", ".." => "I", ".---" => "J",
"-.-" => "K", ".-.." => "L", "--" => "M", "-." => "N", "---" => "O",
".--." => "P", "--.-" => "Q", ".-." => "R", "..." => "S", "-" => "T",
"..-" => "U", "...-" => "V", ".--" => "W", "-..-" => "X", "-.--" => "Y",
"--.." => "Z", "-----" => "0", ".----" => "1", "..---" => "2", "...--" => "3",
"....-" => "4", "....." => "5", "-...." => "6", "--..." => "7", "---.." => "8",
"----." => "9", ".-.-.-" => ".", "--..--" => ",", "..--.." => "?", ".----." => "'",
"-....-" => "-", ".-..-." => '"', ".--.-." => "#", "-...-" => "=", "!" => " "
);
chomp(#message = <>);
print "The message is ";
foreach $char (#message)
{
print $morse_to_plain{$char};
}
You are reading in a string that does not have a matching key in your hash, so the hash value is undefined (uninitialized). It is likely an input problem. Try this for debugging purposes:
print $morse_to_plain{$char} // "Key does not exist: '$char'\n";
For longer strings, you might consider this:
$string =~ s{([-.]+)}{ $morse_to_plain{$1} // $1 }ge;
Which will search for combinations of dots and dashes and translate them to their text equivalent, or themselves if no translation is found.
You should also consider making your hash assignment a bit more readable:
my %morse_to_plain = (
".-" => "A", "-..." => "B", "-.-." => "C", "-.." => "D", "." => "E",
"..-." => "F", "--." => "G", "...." => "H", ".." => "I", ".---" => "J",
"-.-" => "K", ".-.." => "L", "--" => "M", "-." => "N", "---" => "O",
".--." => "P", "--.-" => "Q", ".-." => "R", "..." => "S", "-" => "T",
"..-" => "U", "...-" => "V", ".--" => "W", "-..-" => "X", "-.--" => "Y",
"--.." => "Z", "-----" => "0", ".----" => "1", "..---" => "2", "...--" => "3",
"....-" => "4", "....." => "5", "-...." => "6", "--..." => "7", "---.." => "8",
"----." => "9", ".-.-.-" => ".", "--..--" => ",", "..--.." => "?", ".----." => "'",
"-....-" => "-", ".-..-." => '"', ".--.-." => "#", "-...-" => "=", "!" => " "
);
It will make typos a lot easier to spot. Also, you can make the inverted lookup table rather easily:
my %plain_to_morse = reverse %morse_to_plain;
Remember to always use strict;. Worked well on multiple ... --- ... in a file (all the Morse code I know):
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
my %morse_to_plain=(
".-" =>"A", "-..." => "B", "-.-." => "C", "-.." => "D", "." => "E",
"..-." => "F", "--." => "G", "...." => "H", ".." => "I", ".---" => "J",
"-.-" => "K", ".-.." => "L", "--" => "M", "-." => "N", "---" => "O",
".--." => "P", "--.-" => "Q", ".-." => "R", "..." => "S", "-" => "T",
"..-" => "U", "...-" => "V", ".--" => "W", "-..-" => "X", "-.--" => "Y",
"--.." => "Z", "-----" => "0", ".----" => "1", "..---" => "2", "...--" => "3",
"....-" => "4", "....." => "5", "-...." => "6", "--..." => "7", "---.." => "8",
"----." => "9", ".-.-.-" => ".", "--..--" => ",", "..--.." => "?", ".----." => "'",
"-....-" => "-", ".-..-." => '"', ".--.-." => "#", "-...-" => "=", "!" => " "
);
print "The message is \n";
while (<>) {
chomp;
foreach my $char ( split ' ' ) {
print $morse_to_plain{$char};
}
print "\n";
}

Problem with will_paginate and mongodb

Stack
ruby => 1.9.2-head
rails => 3.0.1
will_paginate => (3.0.pre2)
mongo => (1.1.5)
mongoid => (2.0.0.beta.20)
mongoid_slug => (0.4.6)
Console
r = Radar.criteria
=> #<Mongoid::Criteria:0x00000104753d48 #selector={}, #options={}, #klass=Radar, #documents=[]>
r.map(&:title)
=> ["1", "2", "3", "4", "5", "6"]
r.active.around(Radius.new,current_location).newest.map(&:title)
=> ["6", "5", "4", "3", "2", "1"]
Problem
Step 1
r.active.around(Radius.new,current_location).newest.paginate(:page => 1, :per_page => 3).map(&:title)
=> ["3", "2", "1"] ]
Step 2
r.active.around(Radius.new,current_location).newest.paginate(:page => 2, :per_page => 3).map(&:title)
=>["3", "2", "1"]
In Step1 pagination should return => ["6", "5", "4]
When I change newest to most_commented scope everything works fine.
r.active.around(Radius.new,current_location).most_commented.map(&:title)
=> ["1", "2", "3", "4", "5", "6"]
r.active.around(Radius.new,current_location).most_commented.paginate(:page =>1 ,:per_page => 3).map(&:title)
=> ["1", "2", "3"]
r.active.around(Radius.new,current_location).most_commented.paginate(:page =>2 ,:per_page => 3).map(&:title)
=> ["4", "5", "6"]
Scopes used in conole
scope :most_commented, :order_by => [:comment_count,:desc]
scope :newest, :order_by => [:created_at,:desc]
def self.around(distance,location)
radius = distance.to_rad
near(:coords => location.coords + [radius])
end
ps: I always use new r=Radar.criteria in each example I removed that from output for simplification
I found that .near doesent work well with skip
ruby-1.9.2-head > r = Radar.criteria
Everything works
ruby-1.9.2-head > r.active.near(:coords => ul.coords).newest.map(&:title)
=> ["6", "5", "4", "3", "2", "1"]
Same query but with .skip
ruby-1.9.2-head > r.active.near(:coords => ul.coords).newest.skip(2).map(&:title)
=> []
First query with .skip but without .near
ruby-1.9.2-head > r.active.newest.skip(2).map(&:title)
=> ["4", "3", "2", "1"]