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

I'm currently parsing a line within an xml file. I need to search for the "iL" command and when it is found, select the word right after it. The format of all the items on the line can shift, so I can't search for a particular index number. A sample of the line is: ..... data=company.com -iR 12345 -iL mylink -iF 2 ....... Here is what I am doing now:
@arglist = split(/\ /), $args); foreach $item (@arglist) { if ($item =~ /-iL/) { - need to move to the word right after this value - (mylink) - and assign it to a variable, and break out } }

Replies are listed 'Best First'.
Re: search array for item, move to next item
by pjotrik (Friar) on Oct 17, 2008 at 15:02 UTC
    I'd do it the regex way:
    if ($args =~ /-iL\s+(\w+)/) { print "Found -iL, the value is $1"; }
      got 3 of those replies to work - thank you! i like the quick and dirty regex way....

      Or, to avoid accidents:

      if ($args =~ /(?:\A|\s)-iL(?:\s+([^\s]+)|\s*\Z)/) { print "Found -iL, the value is ", (defined($1) ? "'$1'" : 'absent'), + "\n" ; }
      which:

      • will not find -iL at the end of some word, eg Tref-iL. (Surprisingly there doesn't seem to be a cleaner way of expressing "whitespace or start of string".)
      • uses [^\s] rather than \w -- assuming less about the value of the thing after -iL. (The original fragment used split(/\ /, ...), so strictly should use \ not \s... I have my poet's licence, if you want to see it.)
      • will find a -iL even if it's the last thing in the $args, which may or may not be a good thing to trap as an error in the input.

      Sadly, this doesn't look as pretty any more :-(

      Oh. And FWIW, none of this will cope if the $arg string contains quoted elements -- something way smarter is required !

Re: search array for item, move to next item
by JavaFan (Canon) on Oct 17, 2008 at 14:27 UTC
    You got lured into the idea that any array traversal should be done with for (@array), and that using a C-style for loop is a one way ticket to hell.

    But in this case, using a C-style loop makes sense:

    my $target_word; for (my $i = 0; $i < @arglist; ++$i) { $target_word = $arglist[$i+1], last if $arglist[$i] eq "-iL"; }
    Note that if "-iL" is the last word, undef is assigned to $target_word, which effectively is a no-op.

      Actually it's trivial to still use an iterator-style for loop, you just have to pick something slightly different to iterate over.

      my $target_word; for my $idx ( 0..($#arglist-1) ) { if( $arglist[ $idx ] eq '-iL' ) { $target_word = $arglist[ $idx + 1 ]; last; } }

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

Re: search array for item, move to next item
by toolic (Bishop) on Oct 17, 2008 at 14:59 UTC
    I think Getopt::Long might be able to help:
    use strict; use warnings; use Data::Dumper; use Getopt::Long; my $args = 'data=company.com -iR 12345 -iL mylink -iF 2d'; @ARGV = split /\s+/, $args; my %opt; GetOptions(\%opt, 'iR=i', 'iL=s', 'iF=s'); print 'opt hash ', Dumper(\%opt); print 'ARGV ', Dumper(\@ARGV); __END__ opt hash $VAR1 = { 'iR' => 12345, 'iL' => 'mylink', 'iF' => '2d' }; ARGV $VAR1 = [ 'data=company.com' ];