Suwen has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
I want to extract the last portion of an IP address. For example, 
I want to get uk from www.xxx.xxx.uk, and assign United Kingdom to another variable.
My code is as below, but it dosen't work. I would like to get some advice from you.

my $remote_host = gethostbyaddr(inet_aton ($ip_addr),AF_INET); # get www.xxx.xxx.uk my %CountryCode = { 'com','Comercial', 'uk','The United Kingdom', } # a hash of country name my $CountryName; my @CCode = split /./, $remote_host; # split every portion my $Country = $CCode[-1]; # get the last foreach $key (keys %CountryCode) { if ($Country == $key){ #get the key of country name $CountryName = $CountryCode($key); #assign the key value to a +variable } }
Thank you for your attention
Suwen

Edit Masem 2001-07-26 - CODE tags added, BR tags removed

Replies are listed 'Best First'.
Re: How to do with this hash?
by suaveant (Parson) on Jul 27, 2001 at 00:13 UTC
    my @CCode = split /./, $remote_host; # split every portion

    This line will split on every char and leave you nothing... put a \ in front of the .

    my @CCode = split /\./, $remote_host; # split every portion

    Update ahh... also, instead of your for loop just do

    $CountryName = $CountryCode{$CCode[-1]}; #assign the key value to a va +riable $CountryName = 'Unknown' unless $CountryName;
    to lookup a hash use {} not () (squiggle brackets, not parens)

                    - Ant

Re: How to do with this hash?
by da (Friar) on Jul 27, 2001 at 00:16 UTC
    A comment on the last part of your code (from the 'foreach' onward) - it would be much more efficient to assign long country names like this:
    $CountryName = $CountryCode{$Country} || undef;
    This takes advantage of the lookup capabilities of hashes.

    I'll be back in a minute with some more code... Here ya go:

    #!/bin/perl -w use strict; use Socket; my $ip_addr = '207.127.235.77'; my $remote_host = gethostbyaddr(inet_aton($ip_addr),AF_INET); # get ww +w.xxx.xxx.uk my %CountryCode = ( 'com','Comercial', 'uk','The United Kingdom' ); # a hash of country names my @CCode = split /\./, $remote_host; # split every portion my $Country = $CCode[-1]; # get the last my $CountryName = $CountryCode{$Country} || "Country Unknown"; print $CountryName;

    ___ -DA > perl -MPOSIX -le '$ENV{TZ}="EST";print ctime(1000000000)' Sat Sep 8 20:46:40 2001
Re: How to do with this hash?
by tadman (Prior) on Jul 27, 2001 at 06:03 UTC
    Instead of loading this data from a hash that is defined within your program, you should really be hauling this out of a file such as ISO3166 which defines the countries. The other "special" domains can be hauled out of another file. If you're feeling ambitious enough, another program would munge these two together into a single "config file".

    Another problem you're likely to have is that your program wedges on the gethostbyaddr call. This will block for a long time until it gets an answer. In some cases, the DNS servers you are querying will be down, and you will not get a response. This can limit your rate of resolution to something appallingly low, like 1-2 resolves per minute. A special purpose tool such as DJB's dnsfilter program will do the lookups in parallel. This is part of the djbdns package. These sort of programs are virtually required for reversing a large set of data, such as a log-file from a Web server. dnsfilter is easy enough to use, as it takes input on STDIN.
Re: How to do with this hash?
by jlongino (Parson) on Jul 27, 2001 at 08:58 UTC
    Suwen,
    da gave a good reply to your question but a few corrections were not pointed out. First, on your hash definition:
    my %CountryCode = { 'com','Comercial', 'uk','The United Kingdom', } # a hash of country name
    he corrected it as:
    my %CountryCode = ( 'com','Comercial', 'uk','The United Kingdom' ); # a hash of country names
    Note two things: 1) da changed your {}'s to ()'s (squiggles to parens) when intializing the hash; and 2) you left off a semicolon at the end of the statement.

    Another thing not mentioned is your snippet:

    if ($Country == $key){ #get the key of country name $CountryName = $CountryCode($key); #assign the key value to a varia +ble }
    You should use ($Country eq $key) and not ($Country == $key).
    eq is used for text comparison, == for numeric. suaveant's comment about sqiggles instead of parens applies to the $CountryCode($key) portion which should read $CountryCode{$key}.