Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

Stuck with RegEx (Parsing whois output)

by marsch (Initiate)
on Sep 28, 2004 at 08:40 UTC ( #394500=perlquestion: print w/ replies, xml ) Need Help??
marsch has asked for the wisdom of the Perl Monks concerning the following question:

Hello folks,

I have a little problem like that:

In a file are different sections. In these sections are key-value pairs. Every pair can occur arbitrary times. To be more sophisticated, every section can have several names. Sections are divided by one or more empty lines. An example:

key1: value1_1
key2: value2_1
key2: value2_2
key3: value3_1

key1: value1_1
key2: value2_1
key2: value2_2
key2: value2_3
key3: value3_1

My problem is to find out all lines of a certain key in a distinct section, e.g. find all values of key2 in section 2. I tried with and without look-aheads and look-behinds, all I get is either the first or the last value, but never all of them (should be 3 elements):

my @data = $text =~ /(?<=\{section2\})(?:[^\[\]]+\n)*(?:key2:\s+([^\n] ++?)\s*?\n)/sg; my @data = $text =~ /(?:\{section2\}(?:\{section[\d]+\})*\n)(?:\w+?:\s +*(?:.+?)\s*?\n)*?(?:key2:\s+([^\n]+?)\s*?\n)/sg;

UPDATE: I try to tune Net::XWhois (DENIC parser), which uses an engine like

@matches = $self->{ Response } =~ /${$self->{Parser}}{$key}/sg;

to get the entries, so my task is to set up a new parser.

Is it possible at all to solve this problem?

Thanks for any hint


Comment on Stuck with RegEx (Parsing whois output)
Select or Download Code
Replies are listed 'Best First'.
Re: Stuck with RegEx
by rupesh (Hermit) on Sep 28, 2004 at 09:05 UTC

    A quick script that came to my mind.
    However, I always believe that TIMTOWTDI
    use strict; my $flag = "n"; open FH, '<', 'filename'; foreach (<FH>) { $flag = "n" if /\{section\d+\}/; $flag = "y" if /\{section2\}/; if ($flag =~ /[yY]/) { print $1 if /key2: (.*)$/; } } close FH;
    Update: $flag reset. Thanks to si_lence
      Does this not print all the values for key2 even if they are in a different section that comes after {section2}?
      So you need to reset the $flag variable as soon as you come to the next section.


      thanks for your help. Definitely, this would be fine. But my aim is to tune the Net::XWhois module, especially the DENIC parser. The engine parses the input with one regex:

      @matches = $self->{ Response } =~ /${$self->{Parser}}{$key}/sg;

      This is why I feel bound to that =~ m/.../sg structure. Otherwise I had to rewrite the complete code in order to capture the distinct whois responses...

Re: Stuck with RegEx (Parsing whois output)
by cfreak (Chaplain) on Sep 28, 2004 at 13:40 UTC


      it is similar, indeed, but double key values of one section are overwritten. Additionally, it looks like the examples already provided and needs line-by-line processing.

      Thanks for your help


Re: Stuck with RegEx
by TedPride (Priest) on Sep 28, 2004 at 09:57 UTC
    # where $inp = your file contents... my ($sections, @lines, $key, $value, $p, %hash); foreach (split(/\n\n+/, $inp)) { ($sections, @lines) = split(/\n/, $_); my %thash; foreach (@lines) { ($key, $value) = split(/: /, $_); if ($thash{$key}) { $p = $thash{$key}; push(@$p, $value); } else { $p = [$value]; $thash{$key} = $p; } } while ($sections =~ /{(.*?)}/g) { $hash{$1} = \%thash; } } print $hash{'section2'}->{'key2'}[0] . "\n"; print $hash{'section3'}->{'key2'}[0] . "\n"; $hash{'section2'}->{'key2'}[0] = 'value4_9'; print $hash{'section2'}->{'key2'}[0] . "\n"; print $hash{'section3'}->{'key2'}[0] . "\n";
    As you can see, the sections are just pointers to the actual data, so you can have unlimited section aliases without taking up a lot of space. To print all the contents of key2 in section2:
    $key = $hash{'section2'}->{'key2'}; foreach (@$key) { print "$_\n"; }
Re: Stuck with RegEx
by Jasper (Chaplain) on Sep 28, 2004 at 09:43 UTC
    Something like this might work:
    my $section = 'section1'; # or whichever you're looking in. my $key = 'key2'; # ditto while (<FH>) { for (/$section/ ... /section/) { print $1 if /$key: (\w+)/; } }
    Totally untested. Slightly tested, and I had to change it to the ... range operator and not the .. range operator. (probably wasting my time, though)
Re: Stuck with RegEx (Parsing whois output)
by marsch (Initiate) on Sep 29, 2004 at 08:28 UTC


    Hello folks,

    I finally made it, not too good, but proper. I think there ain't no solution for that problem with one single match as I tried, so I'll use this workaround as I may assume there is a finite number of equal key words:

    @address = $whois =~ m/(?:\{section1\}(?:\{section[\d]+\})*)\n(?:\S*(? +<!key9):\s+[\S]+[^\n]+\n)+(?:key9:\s+([\S]+[^\n]+)\n)(?:key9:\s+([\S] ++[^\n]+)\n)?(?:key9:\s+([\S]+[^\n]+)\n)?(?:key9:\s+([\S]+[^\n]+)\n)?( +?:(?<!key9):[^\n]+\n)*?/gs; for (my $c = scalar @address; $c > 0; --$c) { pop @address unless defined $address[$c - 1]; }

    This is the matched file format:

    key6: key6_1
    key7: key7_1_section1
    key8: key8_1_section1
    key9: key9_1_section1
    key9: key9_2_section1
    key9: key9_3_section1
    key10: key10_1_section1
    key11: key11_1_section1
    key12: key12_1_section1
    key16: key16_1_section1
    key17: key17_1_section1
    key7: key7_1_section2_section3

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://394500]
Approved by Corion
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (7)
As of 2015-11-27 13:09 GMT
Find Nodes?
    Voting Booth?

    What would be the most significant thing to happen if a rope (or wire) tied the Earth and the Moon together?

    Results (729 votes), past polls