MrCromeDome has asked for the wisdom of the Perl Monks concerning the following question:
I have a Perl script that is being deployed at several different sites. To allow each site to customize the appearance of the HTML generated, I have an INI file with a number of NAME=VALUE pairs. What I'm wondering is if there is a way to assign a value to a variable name that is stored in a variable. For example, if I have the following in my INI file:
$NAME=John Smith
I'd like to be able to read $NAME into $var1 and John Smith into $var2, and then assign what's in $var2 to the variable name stored in $var1.
I can currently work around this. Here is my script thus far:
sub read_ini()
{
my @file = read_file("recorder.ini");
my $line = 0;
my $pos = 0;
my $var = "";
my $val;
for(@file)
{
if(substr(@file[$line],0,1) ne "#")
{
$pos = index(@file[$line],"=");
if($pos > 0)
{
$var = substr(@file[$line],0,$pos);
$val = substr(@file[$line],$pos + 1, length(@file[$line]) - $pos);
if($var eq "NAME")
{ $NAME = $val; }
elsif($var eq "OFFICE")
{ $OFFICE = $val; }
# And so on for other instances
}
}
$line++;
}
}
Can I use a hash to accomplish what I described above? I'm sorry for sounding ignorant, but I'm still new to Perl.
Thanks!
Re: Reading from an INI file
by mothra (Hermit) on May 15, 2001 at 18:50 UTC
|
Before you reinvent the wheel (and make all the same mistakes that somebody else already has along the way), you may well be better off using Config::IniFiles.
HTH! | [reply] |
|
And if you're using Perl on a Windows OS, as an alternative to
Config::IniFiles I recommend that
you look into Dave Roth's really useful
Win32::AdminMisc module. It includes a ReadINI (and a WriteINI) function that "understands" section dividers, and ignores lines commented out with semi-colons. There's online documentation at http://www.roth.net/perl/adminmisc/, but here's an example of how it could be used:
foreach my $section (Win32::AdminMisc::ReadINI
('some.ini', '', '')) {
foreach my $key (Win32::AdminMisc::ReadINI
('some.ini', $section, '')) {
my $value = Win32::AdminMisc::ReadINI
('some.ini', $section, $key);
}
}
(Note: if you want to use AdminMisc, either use PPM (if you're using ActiveState), or else use the links at Roth's site. It's on CPAN but http://search.cpan.org for some reason doesn't return a match.)
Finally, in the book Data Munging in Perl (written by davorg), there's a longish discussion about using the high-powered Parse::RecDescent module for parsing INI files.
-- Frag. | [reply] [d/l] |
|
| [reply] |
|
But, you do learn a lot reinventing the wheel, sometimes it is good to write it out...
True, but there are many more problems that people either a.) haven't solved, b.) have solved poorly and so could be solved in a better way. For a more thorough understanding of why one shouldn't reinvent the wheel, look here.
| [reply] |
Re: Reading from an INI file
by suaveant (Parson) on May 15, 2001 at 18:47 UTC
|
yes, there is, you can do
${'STR1'} = 'STR2';
to assign string STR2 to $STR1, however, you are absolutely right
that a hash can accomplish what you want, and is in fact
a much better way to do it than assigning random variables,
especially since it prevents you from overwriting your own
program variables :)
The way I would do it is this...
my %info;
for(@file) {
next if /^#/; skip line if it starts with a hash
chomp; # remove \n Update ACK! forgot this! Doh!
my($name,$val) = split '=', $_, 2; #split line into two
# values, on an = sign
next unless $val; # make sure you got something
$info{$name} = $val;
}
print "$info{OFFICE} - $info{NAME}\n";
very simple. you can also check for values by doing something like
if(exists $info{OFFICE}) {
print "Ofiice: $info{OFFICE}\n";
}
and you can get a list of all your info variables by doing
@keys = keys %info;
try it, and use this to see the results...
for(sort keys %info) {
print "$_: $info{$_}\n";
}
That will print a sorted list of all your keys with their values
Update forgot to chomp... fixed it... oops
- Ant | [reply] [d/l] [select] |
Re: Reading from an INI file
by jeroenes (Priest) on May 15, 2001 at 18:52 UTC
|
Hashes are much better here! Main reason: you don't want
to pollute your namespace with names that can pop up in
those INI files. Well, actually, you want it now, but after
some experience with the results, you will want that you
didn't want it now. {grin}
With an example:
my %ini;
@file = grep m/^[^#]/, @file; #skips comments
for (@file){
chomp; #mpolo is right!
my ($key, $val) = split /=/,2; #splits the line
$ini{ $key } = $val if $key; #if we have a key, store
}
In the remainder of the code, use $ini{$key} to access
the ini values.
You can read up in perldata.
Hope this helps, Jeroen
"We are not alone"(FZ) | [reply] [d/l] |
Re: Reading from an INI file
by mpolo (Chaplain) on May 15, 2001 at 18:52 UTC
|
Yes, a hash can accomplish this: In your file, you can leave off the $ signs, as they will be unnecessary. Then:
open FILE, "recorder.ini"||die "file open failed\n";
chomp(@lines=<FILE>);
foreach(@lines) {
($key,$value)=split(/=/,$_);
$hash{$key}=$value;
}
Now where you would have used $NAME, you can use $hash{'NAME'}. (If I were you, I'd lowercase the key values to make typing easier.)
| [reply] [d/l] |
Re: Reading from an INI file
by suaveant (Parson) on May 15, 2001 at 18:55 UTC
|
Another thing altogether, when you do
for(@file) {
...
}
each element of @file is placed one by one in order into the
variable $_, so you don't need to keep the $line count or
access the lines from the hash, you can just work on the
value in $_
you can also do
for $line (@file) {
...
}
which will put the line in $line instead of $_
when you put arrays in a for loop, be mindful that any changes
you make to the variable will be made to the item in the array,
sometimes that is good, sometimes its not what you want :)
Also I should probably mention that in my previous response when I
used /^#/ that is a regular expression which is acting on
$_, the current line of the file. If you use my example
and put the lines in $line, you would need to make /^#/ into
$line =~ /^#/
to make the regexp look at $line instead of $_
- Ant | [reply] [d/l] [select] |
|
|