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

I have a string that looks like this:

8 changes by 4 users: user1 user2 user3 user4

or...

1 change by user1

That first example can change... number of changes, number of users, and the names. The second one is always the same format.

I want to be able to extract the names in the first example, using matching. (I can't use named groups, stuck in PERL 5.08 hell). I've gotten as far as determining the count for number of users and then building a regex to extract them all. My problem is that I don't know how to address the results in a foreach to then extract the user names. How do I address the results of the matching in a loop? I want to be able to foreach $counter (3..($3)) (I know $1 and $2 are the # of changes and # of users) and then get the other matches using $counter as the subscript?

Replies are listed 'Best First'.
Re: Dynamic matching
by kcott (Archbishop) on Mar 14, 2014 at 00:54 UTC

    G'day flybd5,

    Welcome to the monastery.

    Given you have two distinct formats, I'd probably just use two different regexes.

    #!/usr/bin/env perl -l use strict; use warnings; my @strings = ( '8 changes by 4 users: user1 user2 user3 user4', '1 change by user1', ); for (@strings) { my ($changes, $users, @user_list); if (/:/) { /^(\d+)\D+(\d+)[^:]+:\s+(.+)/; $changes = $1; $users = $2; @user_list = split /\s+/ => $3; } else { /^(\d+) change by (\w+)/; $changes = $1; $users = 1; @user_list = ($2); } print "changes=$changes; users=$users; user_list: @user_list"; }

    Output:

    changes=8; users=4; user_list: user1 user2 user3 user4 changes=1; users=1; user_list: user1

    -- Ken

Re: Dynamic matching
by dave_the_m (Monsignor) on Mar 14, 2014 at 00:40 UTC
    It sounds like you're trying to make life too hard for yourself. Try something like the following. It will need be adjusted slightly depending on the exact composition of whitespace etc.
    my $data = '8 changes by 4 users: user1 user2 user3 user4'; my @users; if ($data =~ /^1 change by (\S+)$/) { @users = $1; } elsif ($data =~ /^\d+ changes by (\d+) users: (.*)$/) { my ($n, $users) = ($1, $2); @users = split ' ', $users; die "user count mismatch\n" unless @users == $n; } else { die "unrecognised format: $data\n"; } print "[$_]\n" for @users;

    Dave.

Re: Dynamic matching
by wind (Priest) on Mar 14, 2014 at 02:24 UTC
    Given the user count is found by just counting the list, the following is sufficient.
    my @strings = ( '8 changes by 4 users: user1 user2 user3 user4', '1 change by user1', ); for (@strings) { if (/^(\d+) change(?: by|s by \d+ users:) (.*)/) { my $changes = $1; my @users = split ' ', $2; print "changes=$changes, users=".@users.", list=@users\n"; } else { warn "Unrecognized string: $_\n"; } }
    Outputs
    changes=8, users=4, list=user1 user2 user3 user4 changes=1, users=1, list=user1
    - Miller
Re: Dynamic matching
by Lennotoecom (Pilgrim) on Mar 14, 2014 at 03:32 UTC
    while(<DATA>){ print "\n$1:" if s/^(\d+ \w+)//; print " $1" while(s/(\w+\d+)//); } __DATA__ 1 change by user23 8 changes by 4 users: user1 user2 user3 user4 6 changes by 4 users: user5 user3 user3 user1 user15 1 change by user1
Re: Dynamic matching
by flybd5 (Initiate) on Mar 14, 2014 at 01:13 UTC
    I knew it, I was needlessly flagellating myself. Thanks, folks. :)