I am trying to process the data in a single file . i have to read the file and create a hash structure,get the value of fruitname append it to fruitCount and fruitValue and delete the line fruitName and write the entire output after the change is done.Given below is the content of file.
# this is a new file
{
date 14/07/2016
time 11:15
end 11:20
total 30
No "FRUITS"
Fruit_class
{
Name "fruit 1"
fruitName "apple.fru"
fruitId "0"
fruitCount 5
fruitValue 6
}
{
Name "fruit 2"
fruitName "orange.fru"
fruitId "1"
fruitCount 10
fruitValue 20
}
}
I tried with following code :
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %hash_table;
my $name;
my $file = '/tmp/fruitdir/fruit1.txt';
open my $fh, "<", $file or die "Can't open $file: $!";
while (<$fh>) {
chomp;
if (/^\s*fruitName/) {
($name) = /(\".+\")/;
next;
}
s/(fruitCount|fruitValue)/$name\.$1/;
my ($key, $value) = split /\s+/, $_, 2;
$hash_table{$key} = $value;
}
print Dumper(\%hash_table);
This is not working . I need to append the value of fruitname and print the the entire file content as output. Any help will be appreciated.Given below is the output that i got.
$VAR1 = {
'' => undef,
'time' => '11:15 ',
'date' => '14/07/2016',
'{' => undef,
'#' => 'this is a new file',
'total' => '30 ',
'end' => '11:20 ',
'No' => '"FRUITS"',
'Fruit_class' => undef,
'}' => undef
};
Expected hash as output:
$VAR1 = {
'Name' => '"fruit 1"',
'fruitId' => '"0" ',
'"apple_fru".fruitValue' => '6 ',
'"apple_fru".fruitCount' => '5'
'Name' => '"fruit 2"',
'fruitId' => '"0" ',
'"orange_fru".fruitValue' => '10 ',
'"orange_fru".fruitCount' => '20'
};
One word of advice before I continue:
Document your code
There are several logic errors in your code which I think you would have recognized if you wrote down what you thought each line was supposed to do. First, write down the algorithm that you would like to implement, then document how each step in the code implements a step in the algorithm. At the end you'll be able to see what you missed, or what part is not working.
Here are the errors that I see
You aren't ignoring lines that you shouldn't be parsing. For example, you're grabbing the '}' and '{' lines.
You aren't actually storing the name of the fruit. You grab it, but immediately start the next loop without storing it.
You're not keeping track of each structure. You need to start a new structure for each fruit.
Do you really want to keep the double quotes in the values?
Other things to worry about:
Are you guaranteed that the list of attributes is in that order? For example, can Name come last?
Here's some code which does what I think you want.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %hash_table;
my $name;
my #fruit;
my $file = '/tmp/fruitdir/fruit1.txt';
open my $fh, "<", $file or die "Can't open $file: $!";
while (<$fh>) {
chomp;
# save hash table if there's a close bracket, but
# only if it has been filled
if ( /^\s*}\s*$/ ) {
next unless keys %hash_table;
# save COPY of hash table
push #fruit, { %hash_table };
# clear it out for the next iteration
%hash_table = ();
}
# only parse lines that start with Name or fruit
next unless
my ( $key, $value ) =
/^
# skip any leading spaces
\s*
# parse a line beginning with Name or fruitXXXXX
(
Name
|
fruit[^\s]+
)
# need space between key and value
\s+
# everything that follows is a value. clean up
# double quotes in post processing
(.*)
/x;
# remove double quotes
$value =~ s/"//g;
if ( $key eq 'Name' ) {
$name = $value;
}
else {
$key = "${name}.${key}";
}
$hash_table{$key} = $value;
}
print Dumper \#fruit;
and here's the output:
$VAR1 = [
{
'fruit 1.fruitValue' => '6',
'fruit 1.fruitName' => 'apple.fru',
'Name' => 'fruit 1',
'fruit 1.fruitCount' => '5',
'fruit 1.fruitId' => '0'
},
{
'fruit 2.fruitName' => 'orange.fru',
'fruit 2.fruitId' => '1',
'fruit 2.fruitCount' => '10',
'fruit 2.fruitValue' => '20',
'Name' => 'fruit 2'
}
];
Related
I have some data in input file
user date="" name="" id="small"
user date="" name="" id="sample test"
user date="" name="" id="big city"
I want to get only id's from above file
code::-
use strict;
use warnings;
my $input = "location\input.txt";
open("FH","<$input") or die;
while(my $str = <FH>)
{
my #arr = split(/ /,$str);
$arr[2] =~ s/id=//g;
$arr[2] =~ s/"//g;
print "$arr[2]\n";
}
close("FH");
Output :
small
sample
big
Note :: Here I'm not able to print complete word like "small test", "big city"
Expectation : I need to get complete word "sample test" and "big city" anyone please help me on this
If you know the format will always have quotes after id, you can do:
use feature qw(say);
use strict;
use warnings;
open my $fh, "<", "location/input.txt" or die $!;
while (my $line = <$fh>) {
my ($id) = $line =~ /id="(.*?)"/;
say $id;
}
Breaking down that complicated line we have:
$line =~ /id="(.*?)"/: match id="..." and grab the smallest possible
.... If you use .* instead, you will grab up until the last " of the line, which might belong to another field. This is not the case for id, but try it with date and you'll see.
my ($id) = ...: process the regex match in list context, which returns the capture groups, and assign it pairwise to the list ($id). Concretely, this stuffs the matched value in $id
say $id: prints $id with an automatic newline after it.
A nice module for handling quoted strings is Text::ParseWords. It is a core module too, making it even handier. You can use it here to easily split the string on whitespace, then parse the result into hash keys.
use strict;
use warnings;
use Data::Dumper;
use Text::ParseWords;
while (<DATA>) {
chomp;
my %data = map { my ($key, $data) = split /=/, $_, 2; ($key => $data); } quotewords('\s+', 0, $_);
print Dumper \%data;
}
__DATA__
user date="" name="" id="small"
user date="" name="" id="sample test"
user date="" name="" id="big city"
Output:
$VAR1 = {
'user' => undef,
'name' => '',
'date' => '',
'id' => 'small'
};
$VAR1 = {
'name' => '',
'date' => '',
'id' => 'sample test',
'user' => undef
};
$VAR1 = {
'id' => 'big city',
'date' => '',
'name' => '',
'user' => undef
};
A simplified version to extract data of interest
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
while(<DATA>) {
my %d = /(\w+)="(.*?)"/g;
say 'id: ' . $d{id};
say Dumper(\%d);
}
__DATA__
user date="" name="" id="small"
user date="" name="" id="sample test"
user date="" name="" id="big city"
Output
id: small
$VAR1 = {
'date' => '',
'id' => 'small',
'name' => ''
};
id: sample test
$VAR1 = {
'id' => 'sample test',
'date' => '',
'name' => ''
};
id: big city
$VAR1 = {
'name' => '',
'id' => 'big city',
'date' => ''
};
Below is the log file content and I'm reading the log file and grouping it based on the string - JIRA.
JIRA: COM-1234
Program:Development
Reviewer:John Wick
Description:Genral fix
rev:r345676
------------------------------------------
JIRA:COM-1234
Program:Development
Reviewer:None
Description:Updating Received
rev:r909276
------------------------------------------
JIRA: COM-6789
Program:Testing
Reviewer:Balise Mat
Description:Audited
rev:r876391
------------------------------------------
JIRA: COM-6789
Program:Testing
Reviewer:Chan Joe
Description:SO hwat
rev:r698392
------------------------------------------
JIRA: COM-6789
Program:Testing
Reviewer:Chan Joe
Description:Paid the Due
rev:r327896
------------------------------------------
My requirement is , iterate thru every unique JIRA value - COM-1234 , COM-6789, etc and store the following or immediate details in to individual array like
(for COM-1234)
#prog = Development;
#Reviewer = John Wick;
#Description = Genral fix;
#rev = r345676;
(for COM-6789)
#prog = Testing;
#Reviewer = Balise Mat;
#Description = Audited;
#rev = r876391;
If the JIRA value is identical , say COM-1234 repeated 2 times and COM-6789 for 3 times , still push only the following or immediate details to the respective arrays. (i.e. values of the keys 'Program','Reviewer' ....)
(COM-1234)
#prog = Development;
#Reviewer = None;
#Description = Updating Received ;
#rev = r909276;
I'm very new to Perl and I can manage to reach only for the unique values and not sure how to push the following values to individual arrays.
Any inputs will be really helpful. Thanks.
My incomplete code:
#!/usr/bin/perl
use warnings;
use Data::Dumper;
$/ = "%%%%";
open (AFILE, ""<", ""D:\\mine\\out.txt");
while (<AFILE>)
{
#temp = split(/-{20,}/, $_);
}
close (AFILE);
my %jiraHash;
for ($i=0; $i<=#temp; $i++) {
if (($temp[$i] =~ /(((JIRA|SVN)\s{0,1}:(\s{0,2}[A-Za-z0-9-\s]{4,9}),
{0,1}\s{0,2}){1,5})\nProgram\s{0,1}:\s{0,2}Development/) ||
($temp[$i] =~ /(((JIRA|SVN):(\s{0,2}[A-Za-z0-9-\s]{4,9}),
{0,1}\s{0,2}){1,5})\nProgram\:\s{0,2}Testing/)) {
$jiraId = $2;
$jiraId =~ s/JIRA\s*\://;
$temp[$i] =~ s/\w{3,}\s?:\s?//g;
#print "==>$jiraId\n";
$jiraHash{$jiraId} = $temp[$i];
} else {
#print "NOT\n";
}
}
print Dumper(%jiraHash);
I'm planning display as HTML report in below format
Program: Development
FOR ID: COM-1234
Revision Reviewer Comment
r345676 John Wick Genral fix
Revision Reviewer Comment
r909276 None Updating Received
Program: Testing
FOR ID: COM-6789
Revision Reviewer Comment
r876391 Balise Mat Audited
Revision Reviewer Comment
r698392 Chan Joe SO hwat
Revision Reviewer Comment
r327896 Chan Joe Paid the Due
It sounds like this data should be in a database.
But it is relatively simple to parse it into a data structure. Here, I've gone for a hash where the key is the Jira identifier and the value is a reference to an array that contains hash references. Each of the referenced hashes contains the details from one of the records.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
my #records = do {
local $/ = '------------------------------------------';
<>;
};
chomp #records;
my %jira;
foreach (#records) {
next unless /\S/;
my %rec = /^(\w+):\s*(.+?)$/mg;
push #{$jira{$rec{JIRA}}}, \%rec;
}
say Dumper \%jira;
When you run it on your given data, you get this output:
$VAR1 = {
'COM-6789' => [
{
'Program' => 'Testing',
'JIRA' => 'COM-6789',
'rev' => 'r876391',
'Reviewer' => 'Balise Mat',
'Description' => 'Audited'
},
{
'Program' => 'Testing',
'JIRA' => 'COM-6789',
'rev' => 'r698392',
'Reviewer' => 'Chan Joe',
'Description' => 'SO hwat '
},
{
'Program' => 'Testing',
'JIRA' => 'COM-6789',
'rev' => 'r327896',
'Reviewer' => 'Chan Joe',
'Description' => 'Paid the Due'
}
],
'COM-1234' => [
{
'Program' => 'Development',
'JIRA' => 'COM-1234',
'rev' => 'r345676',
'Reviewer' => 'John Wick ',
'Description' => 'Genral fix'
},
{
'Program' => 'Development',
'JIRA' => 'COM-1234',
'rev' => 'r909276',
'Reviewer' => 'None',
'Description' => 'Updating Received '
}
]
};
From there, it's relatively simple to get a display of the data:
foreach my $j (keys %jira) {
say "JIRA: $j";
foreach (#{$jira{$j}}) {
say "Program: $_->{Program}";
say "Revision: $_->{rev}";
# etc...
}
}
Since your data is nicely structured into one line per data item, and since Perlby default processes input line by line, I suggest doing that instead of messing with $/ or regexps to split the input records. This does require you to remember the JIRA issue ID from the first line of each record, but that's simple — just store it in a variable declared outside the loop, like this:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my %records;
my $jiraID;
while (<>) {
chomp;
if (/^JIRA: (.*)/ and not defined $jiraID) {
$jiraID = $1;
$records{$jiraID} = {}; # wipe out any old data for this ID
} elsif (/^(Program|Reviewer|Description|rev):(.*)/ and defined $jiraID) {
$records{$jiraID}{$1} = $2;
} elsif (/^-{20,}$/) {
undef $jiraID; # end of record
} else {
die qq(Unexpected input line "$_");
}
}
print Dumper(\%records);
The code above reads its input from any file(s) provided as command line arguments, or from standard input if there aren't any, using the <> default input operator. If you want to read from a specific file handle that you've opened yourself, you can of course provide one.
Note that the code above stores only the last record for each ID. If you want to store all of them in an array, replace the line:
$records{$jiraID} = {}; # wipe out any old data for this ID
with:
push #{$records{$jiraID}}, {}; # start new record for this ID
and change the line:
$records{$jiraID}{$1} = $2;
to:
$records{$jiraID}[-1]{$1} = $2;
Ps. The regexps in the code above are based on your sample data. If your real data has other types of lines in it (or variations e.g. in the amount of whitespace), you'll need to adjust them to match those lines too. I coded the script to die if it sees anything unexpected, so it's easy to tell if that happens.
Update: Based on the sample output you posted while I was writing this answer, it looks like you want to group the data by both the JIRA and the Program lines. That's easy enough to do as well, e.g. like this:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my %records;
my $jiraID, $progID;
while (<>) {
chomp;
if (/^JIRA:\s*(.*)/ and not defined $jiraID) {
$jiraID = $1;
} elsif (/^Program:\s*(.*)/ and defined $jiraID and not defined $progID) {
$progID = $1;
push #{$records{$jiraID}{$progID}}, {}; # start new record for these IDs
} elsif (/^(Reviewer|Description|rev):(.*)/ and defined $progID) {
$records{$jiraID}{$progID}[-1]{$1} = $2;
} elsif (/^-{20,}$/) {
undef $jiraID, $progID; # end of record
} else {
die qq(Unexpected input line "$_");
}
}
print Dumper(\%records);
Note that I grouped the output data structure first by the JIRA ID and then by the program, but of course those would be easy to swap (or even combine into a single hash key, if you prefer).
This doesn't handle the final output, but this may be a simplified approach to storing lists of lists for each hash element (ticket id), along with some sample output at the end. It's not formatted the way you want, but that should be easy enough:
use strict;
my (%jira, #values, $ticket_id);
open my $IN, '<', 'jira.txt' or die;
while (<$IN>) {
chomp;
my ($key, $val) = split /:\s*/;
if ($key eq 'JIRA') {
if (#values) {
push #{$jira{$ticket_id}}, [ #values ];
#values = ();
}
$ticket_id = $val;
} elsif ($key eq 'Program') {
$values[0] = $val;
} elsif ($key eq 'Reviewer') {
$values[1] = $val;
} elsif ($key eq 'Description') {
$values[2] = $val;
} elsif ($key eq 'rev') {
$values[3] = $val;
}
}
close $IN;
push #{$jira{$ticket_id}}, [ #values ];
while (my ($ticket, $ref) = each %jira) {
print "$ticket =>\n";
foreach my $line_ref (#$ref) {
print join "\t", #$line_ref, "\n";
}
}
Sample output:
COM-1234 =>
Development John Wick Genral fix r345676
Development None Updating Received r909276
COM-6789 =>
Testing Balise Mat Audited r876391
Testing Chan Joe SO hwat r698392
Testing Chan Joe Paid the Due r327896
I have a Perl function (named readDicomFile) which ends thusly:
return { 'fileProperties' => \%fileProperties, 'filehandle' => *FH, 'buffersize' => $buffersize };
the code that calls it looks like this:
$file = readDicomFile( $ARGV[0] );
#use Data::Dumper;
#print Dumper $file;
my #imageData;
local *FH = $file->{filehandle};
while ( read(FH, $_, $file->{buffersize}) ) {
push #imageData, unpack( 'S' x ( $file->{buffersize}/($file->{fileProperties}->{bitsAllocated}/8) ), $_ );
}
print "DEBUG: found ", (scalar #imageData), " elements\n";
I get this output:
Can't use string ("0") as a HASH ref while "strict refs" in use at ./test.pl line 17.
DEBUG: found 262156 elements
When I try to figure out what's happening with my data structure, I uncomment the two lines for using Data::Dumper and I get this:
$VAR1 = {
'fileProperties' => {
'echoNumber' => '',
'highBit' => 11,
'rows' => 512,
'bitsAllocated' => 16,
'modality' => 'CT',
'echoTime' => '',
'windowCenter' => '200',
'studyDescription' => 'CT SINUS / FACIAL WITH CONTRAST ',
'repetitionTime' => '',
'sequenceName' => '',
'method' => 'perl method',
'seriesNumber' => '502 ',
'imageNumber' => '0 ',
'windowWidth' => '50',
'trailer' => 0,
'pixelRepresentation' => 0,
'sliceLocation' => '',
'bitsStored' => 12,
'ultrasoundColorData' => '',
'rescaleIntercept' => 0,
'photometricInterpretation' => 'MONOCHROME2 ',
'description' => 'Patient Protocol',
'imageDataType' => '',
'imagePosition' => '',
'columns' => 512,
'studyDate' => '20140505'
},
'filehandle' => *Radiology::Images::FH,
'buffersize' => '1024'
};
I've played around with several different idioms for returning the hash values from the function (like passing back a hash or a hashref), but I'm always getting the same error.
Does anyone have insight into my problem?
Thanks in advance.
EDIT:
I've been playing around with this all afternoon. Here is the entirety of the current test.pl
#!/usr/bin/perl -w
use lib '/etc/perl';
use strict;
use Radiology::Images;
my $file = $ARGV[0];
$file = readDicomFile( $file );
print STDERR "DEBUG: $file->{fileProperties}->{bitsAllocated}\n";
my #imageData;
# while ( $readsize = read ( $file->{filehandle}, $_, $file->{buffersize} ) ) {
# push #imageData, unpack( 'S' x ( $file->{buffersize}/($file->{fileProperties}->{bitsAllocated}/8) ), $_ );
# }
my $readsize;
my $imagesize = $file->{fileProperties}->{columns} * $file->{fileProperties}->{rows};
print "DEBUG: should find $imagesize elements\n";
while ( $imagesize > 0 ) {
$readsize = read ( $file->{filehandle}, $_, $file->{buffersize} );
push #imageData, unpack( 'S' x ( $readsize/( $file->{fileProperties}->{bitsAllocated}/8 ) ), $_ );
$imagesize -= $readsize /( $file->{fileProperties}->{bitsAllocated}/8 );
}
print "DEBUG: found ", (scalar #imageData), " elements\n";
...which gives me this output
DEBUG: 16
DEBUG: should find 262144 elements
Can't use string ("0") as a HASH ref while "strict refs" in use at /root/test.pl line 7.
DEBUG: found 262144 elements
...HOWEVER, when I change the 'while' loop in line #15 to
while ( $imagesize > 34816 ) {
I get this output:
DEBUG: 16
DEBUG: should find 262144 elements
DEBUG: found 227328 elements
So, it would appear that something I'm doing in a loop between lines 15 and 18 causes an error that goes back in time to line 7. Thus, my problem has never been with passing the hash back from my function. ??
BTW, the number 34816 was arrived experimentally. 34816 doesn't trigger the error, 34815 does.
Given this is looking completely whacky and given that the code works the way I think it is supposed to despite the error, I guess I'll just assume it is a language bug and turn my attention to just suppressing the error message.
2nd EDIT:
This is test.pl now:
#!/usr/bin/perl -w
use lib '/etc/perl';
use strict;
use Radiology::Images;
my $file = $ARGV[0];
$file = readDicomFile( $file );
my #imageData;
my $readsize;
while ( $readsize = read ( $file->{filehandle}, $_, $file->{buffersize} ) ) {
push #imageData, unpack( 'S' x ( $readsize/($file->{fileProperties}->{bitsAllocated}/8) ), $_ );
}
print "DEBUG: found ", (scalar #imageData), " elements\n";
gives me this output:
Can't use string ("0") as a HASH ref while "strict refs" in use at /root/test.pl line 9.
DEBUG: found 5638203 elements
if I comment out the 'use strict' line, I get:
Use of uninitialized value in ref-to-glob cast at /root/test.pl line 9.
Use of uninitialized value in read at /root/test.pl line 9.
read() on unopened filehandle at /root/test.pl line 9.
DEBUG: found 5638215 elements
I, uh, obviously...don't understand this....
You need to return a reference to your file handle:
return {
'fileProperties' => \%fileProperties,
'filehandle' => \*FH, # <--- reference.
'buffersize' => $buffersize,
};
And then when reading, you can work directly on the filehandle, you don't have to transfer it to a fileglob:
# local *FH = $file->{filehandle}; <--- Not Needed. Below, just use the lexical fh
while ( read($file->{filehandle}, $_, $file->{buffersize}) ) {
If you work with lexical file handles from the very beginning, it becomes a lot more obvious how to pass them:
open my $fh, '<', 'myfile.txt' or die "Can't open: $!";
return {
'fileProperties' => \%fileProperties,
'filehandle' => $fh,
'buffersize' => $buffersize,
};
The variables $var and $var2 in the following code hold same value but behave differently with respect to eval().
Source:
use Data::Dumper;
sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
$string =~ s/\R//g;
return $string;
}
my $var2="";
$var2.="{id=>1962}";
$var2.=",{id=>1645}";
$var2.=",{id=>905}";
$var2.=",{id=>273}";
$var2.=",{id=>1800}";
$var2.=",{id=>21}";
$var2.=",{id=>1639}";
$var2.=",{id=>55}";
$var2.=",{id=>57}";
$var2.=",{id=>59}";
$var2.=",{id=>420}";
$var2.=",{id=>418}";
$var2="[".$var2."]";
print Dumper $var2;
print Dumper eval($var2); #evaluates to an ARRAY
my $filename = "sample.txt";
open(FILE, $filename) or die "Can't read file 'filename' [$!]\n";
$document = <FILE>;
close (FILE);
$document=trim($document);
#data = split(',', $document);
my $var = "";
foreach my $val (#data) {
$var.="{id=>".$val."},";
}
chop($var);
$var = "[".$var."]";
print "\n";
if ($var eq $var2){
print "var and var2 stringwise equal\n" ;
}else{
print "var and var2 stringwise not equal\n" ;
}
print Dumper $var;
print Dumper eval($var); #error
exit(0);
Content of sample.txt:
1962,1645,905,273,1800,21,1639,55,57,59,420,418
Output:
$VAR1 = '[{id=>1962},{id=>1645},{id=>905},{id=>273},{id=>1800},{id=>21},{id=>1639},{id=>55},{id=>57},{id=>59},{id=>420},{id=>418}]';
$VAR1 = [
{
'id' => 1962
},
{
'id' => 1645
},
{
'id' => 905
},
{
'id' => 273
},
{
'id' => 1800
},
{
'id' => 21
},
{
'id' => 1639
},
{
'id' => 55
},
{
'id' => 57
},
{
'id' => 59
},
{
'id' => 420
},
{
'id' => 418
}
];
var and var2 stringwise equal
$VAR1 = '[{id=>1962},{id=>1645},{id=>905},{id=>273},{id=>1800},{id=>21},{id=>1639},{id=>55},{id=>57},{id=>59},{id=>420},{id=>418}]';
Insecure dependency in eval while running with -T switch at assignment.pl line 51.
Can anyone tell why "eval($var)" doesn't get evaluated despite having same value as that of $var2 ?
While $var might be the same as $var2 in your specific case of data, it isn't necessarily always that case. You script also doesn't forbid the eval even if it is not the same.
Thus, the tainted check is right to complain about the insecure eval, as it is intended to detect potentially unsafe operations which your eval($var) definitely is.
Generally, you should try to avoid eval wherever you can, as it is a prime source of remote-code-execution vulnerabilities. Instead, you should try to parse your data structures using other, safer means, e.g. by using split on your input data and then looping over the resulting array to produce your desired data structure.
This is perl Taint Mode doing exactly what it's supposed to be doing. You're reading in data from an external resource, and perl -T is not allowing you to run tainted data through eval since that literally could end up doing anything (very insecure).
In order to launder your data you simply need to run in through a regular expression to verify what it is. Replace the following line:
#my #data = split(',', $document);
my #data = $document =~ m/(\d+)/g;
Because we're running the external document data through a regex, the values in #data will no longer be tainted and can be eval'd.
Either way, I'd advise against using eval at all unless there is a specific reason why you need it. The following accomplishes the same thing without the need for an eval
my $var = [map {id => $_}, #data];
So I know that there are hundred examples on Stack overflow, and in fact i have used all the information from there - so this is what i have
use strict;
use warnings;
use Data::Dumper;
my $head= undef;
my $tail=\$head;
open FILE, "<datastored.txt" or die $!;
while (<FILE>){
my $node = {
"data" => $_ ,
"next" => undef
};
$$tail=$node;
$tail = \$node->{"next"};
};
print Dumper $head; #before reversing
$head = reverse_list($head);
print Dumper $head; #after reversing
sub reverse_list{
my ($list) =#_[0];
my $previous = undef;
while ($list->{next}){
$forward = $list->{next};
$list->{next}= $previous;
$previous = $list;
$list=$forward;
};
return $previous;
};
and this is the output I get
#this is the output before reversing (normal linked list)
$VAR1 = {
'next' => {
'next' => {
'next' => {
'next' => undef,
'data' => 'line 4
'
},
'data' => 'line 3
'
},
'data' => 'line 2
'
},
'data' => 'line 1
'
};
#this is the linked list after reversing (WITHOUT THE LAST DATA VARIABLE - "line 4")
$VAR1 = {
'next' => {
'next' => {
'next' => undef,
'data' => 'line 1
'
},
'data' => 'line 2
'
},
'data' => 'line 3
'
};
Note - the content of the file datastored.txt is simply
line 1
line 2
line 3
line 4
So my question is where is the data "line 4" gone and what should i change to ACTUALLY reverse the linked list without losing any value.
Your reversal sub-routine is almost correct. However, it misses the last entry (i.e. adding it in the final reversed list) because of the condition you are using. You have two options:
Change the while ($list->{next}) to while ($list) and make the code more idiomatic.
Add a $list->{next}= $previous; after the end of the while loop to add back the last remaining node to your reversed list. (Think of a list of two elements and see what your code does).