Hue-Bond has asked for the wisdom of the Perl Monks concerning the following question:

I'm about to parse the output of xlsclients -la. It's like this:

Window 0x800022: Machine: genus Name: xterm Icon Name: xterm Command: xterm -u8 -geometry 156x62+190+-2 Instance/Class: xterm/XTerm Window 0xc00022: Machine: genus Name: ~ Icon Name: psh Command: xterm -e /usr/bin/psh Instance/Class: xterm/XTerm Window 0xe00001: Machine: genus Name: Gecko Icon Name: mozilla-bin Command: mozilla-bin Instance/Class: mozilla-bin/Mozilla-bin

There's no blank link between "paragraphs" so I can't use $/ = "\n\n". I want to do something simple that gives me whole paragraphs without eating anything (so $/ = "\nWindow" wouldn't fit). I'm thinking about reading six lines at a time but I find it ugly:

open my $fd, 'xlsclients -la|' or die "open: $!"; WHILE: while (1) { my @para; foreach (1..6) { my $line = <$fd>; defined $line or last WHILE; push @para, $line; } print "@para\n"; ## quotes intended in this small example } close $fd;

Is there anything more I can do?

--
David Serrano

Replies are listed 'Best First'.
Re: Reading chunks of text
by holli (Abbot) on Aug 21, 2006 at 08:06 UTC
    You can use the fact that all lines of the paragraphs are indented, but the first line.
    my @p; while (<DATA>) { push @p, [], if /^Window/; push @{$p[-1]}, $_; }
    or maybe you want a hash and use the window handles as keys:
    my %h; while (<DATA>) { $key = $1, next if /^Window ([^:]+)/; push @{$h{$key}}, $_; }


    holli, /regexed monk/
Re: Reading chunks of text
by cog (Parson) on Aug 21, 2006 at 08:06 UTC
    Is there anything more I can do?

    Yes, there is.

    while (my @a = grep defined, map scalar <$fd>, 1 .. 6) { # do whatever you want with @a, which has 6 lines }

    I asked a similar question, two years ago.

Re: Reading chunks of text
by shmem (Chancellor) on Aug 21, 2006 at 08:12 UTC
    Maybe this? (untested)

    while(my $line = <$fd>) { $line =~ /^Window/ ? push (@para, $line) : ($para[$#para] .= $line); }

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Reading chunks of text
by Fletch (Bishop) on Aug 21, 2006 at 12:58 UTC

    Actually that's coincidentally valid YAML:

    $ xlsclients -la | perl -MYAML -MData::Dumper -le '$x = do { local $/; + <>}; print Data::Dumper::Dumper( YAML::Load( $x ) )' $VAR1 = { 'Window 0x600001' => { 'Command' => 'xemacs', 'Machine' => 'foo', 'Icon Name' => 'xemacs', 'Instance/Class' => 'xemacs/Emacs', 'Name' => 'xemacs' }, 'Window 0xa0000e' => { 'Command' => 'xterm -display :11 -geo +m +0-25', 'Machine' => 'bar.phydeaux.org', 'Icon Name' => 'fletch@bar:~', 'Instance/Class' => 'xterm/XTerm', 'Name' => 'fletch@bar:~' } };
Re: Reading chunks of text
by GrandFather (Saint) on Aug 21, 2006 at 11:23 UTC

    An interesting but fragile technique is to alter the input record seperator $/:

    use strict; use warnings; local $/ = "Window "; while (<DATA>) { chomp; next if ! length; my $paragraph = $/ . $_; print "$paragraph\n"; } __DATA__ Window 0x800022: Machine: genus Name: xterm Icon Name: xterm Command: xterm -u8 -geometry 156x62+190+-2 Instance/Class: xterm/XTerm Window 0xc00022: Machine: genus Name: ~ Icon Name: psh Command: xterm -e /usr/bin/psh Instance/Class: xterm/XTerm Window 0xe00001: Machine: genus Name: Gecko Icon Name: mozilla-bin Command: mozilla-bin Instance/Class: mozilla-bin/Mozilla-bin

    Prints:

    Window 0x800022: Machine: genus Name: xterm Icon Name: xterm Command: xterm -u8 -geometry 156x62+190+-2 Instance/Class: xterm/XTerm Window 0xc00022: Machine: genus Name: ~ Icon Name: psh Command: xterm -e /usr/bin/psh Instance/Class: xterm/XTerm Window 0xe00001: Machine: genus Name: Gecko Icon Name: mozilla-bin Command: mozilla-bin Instance/Class: mozilla-bin/Mozilla-bin

    DWIM is Perl's answer to Gödel