Sadly, Perl will only capture the last match of capture with a qualifier,
so that just won't work.  The split function really is the simplest and
most elegant solution for this sort of problem (you have a string with a
delimiter and you want the pieces).  All of that said, if you are willing
to modify the regex you can say

my $s = "command arg1 arg2 arg3 arg4";
my @args = $s =~ /(?:\s+(\w+))/g;

for my $arg (@args) {
print "$arg\n";
}

However, this does not allow you to check the command is correct.

Another option, and I would in no way claim this is an elegant solution, is
to use code execution in the middle of the regex with (?{}) to pull out the
matched fields:

@args = ();

my $start;
$s =~ m{
\w+ # command
\s
(?{$start = pos;}) # capture the first start position
(?:
\w+ # the argument
# capture the argument
(?{ push @args, substr $s, $start, pos() - $start; })
# optional delimiter and capture the next start
(?: \s+ (?{ $start = pos; }))?
)+
}x;

for my $arg (@args) {
print "$arg\n";
}

Of course, all of these solutions are bound to fail when you hit the real
world (assuming the command is a Unix command) as arguments are allowed to
have spaces in them if they are quoted.  There is a way to do this with
regex, but balancing the quotes is far more pain than it is worth.  A
simple regex to tokenize the string plus some logic to put the quoted
sections back together will allow you to extract the arguments from the
string:

#!/usr/bin/perl

use strict;
use warnings;

my $s = qq("command with space" arg1 "arg 2" "arg3");

my @parts = $s =~ /([ ]+|"|\w+)/g;

my @args;
my $in_string = 0;
my $buf = "";
while (@parts) {
my $part = shift @parts;

# ditch the delimiters if not in a string
next if not $in_string and $part =~ / /;

# in strings, a " means end the string
# otherwise, just build up a buffer of the things
# in the string
if ($in_string) {
if ($part eq '"') {
$in_string = 0;
push @args, $buf;
$buf = "";
} else {
$buf .= $part;
}
next;
}

# if not in a string, " means start a string
if ($part eq '"') {
$in_string = 1;
next;
}

# if not a delimiter or a ", then this is just a normal token
push @args, $part;
}

shift @args; #ditch the command

for my $arg (@args) {
print "$arg\n";
}

Of course, this still doesn't handle Unix commands properly as you can
escape " and use ' to create strings, but those details are left as an
exercise for the reader.




On Wed, Mar 1, 2017 at 4:04 AM Luca Ferrari <fluca1...@infinito.it> wrote:

> Hi all,
> I'm not sure if this is possible, but imagine I've got a line as follows:
>
> command arg1 arg2 arg3 arg4 ...
>
> I would like to capture all args with a single regexp, possibly with a
> named capture, but I don't know exactly how to do:
>
> my $re = qr/command\s+(?<arg>\w+)+/;
>
> the above of course is going to capture only the first one (one shoot)
> or the last one within a loop.
> How can I extract the whole array of arguments?
>
> Please note, a raw solution is to remove the command and split, but
> I'm asking for a more elegant solution.
>
> Thanks,
> Luca
>
> --
> To unsubscribe, e-mail: beginners-unsubscr...@perl.org
> For additional commands, e-mail: beginners-h...@perl.org
> http://learn.perl.org/
>
>
>

Reply via email to