Here is another solution. There are probably a million ways to do this, so...
#!/usr/bin/perl -w
use strict;
use warnings;
my $TEXT = <<'END';
>James
>40
>James
>4
>John
>35
>James
>26
>John
>31
>James
>15
>Pete
END
$TEXT =~ tr|a-zA-Z0-9||cd; # Remove everything except letters a
+nd numbers
my @ARRAY = SplitNumbers($TEXT); # Split numbers vs letters
if (@ARRAY & 1) { pop(@ARRAY); } # Remove last element if it has no n
+umber following it.
my %HASH; # This is used as a global here
for (my $i = 0; $i < @ARRAY; $i+=2)
{
if (exists($HASH{$ARRAY[$i]})) { $HASH{$ARRAY[$i]} .= ', '; }
$HASH{$ARRAY[$i]} .= $ARRAY[$i+1];
}
print GetList('James');
print GetList('John');
print GetList('Pete');
print GetList('Bob');
exit;
##################################################
# Returns the named list in nicely formatted way.
#
# Usage: STRING = GetList(NAME)
#
sub GetList
{
@_ or return '';
my $NAME = shift; # Get first argument, which is the 'NAME'
return "\n $NAME = [" . (exists($HASH{$NAME}) ? $HASH{$NAME} : '')
+ . "]\n";
}
##################################################
#
# Splits a string along numbers and returns an
# array of alternating numbers and text.
# Usage: ARRAY = SplitNumbers(STRING)
#
# Example: SplitNumbers('abc45tt-35203.19') -> ["abc", 45, "tt-", 3520
+3, ".", 19]
#
sub SplitNumbers
{
defined $_[0] or return ();
my ($PTR, $PREV, $LEN, $TYPE, @A) = (0, -1, length($_[0]));
$LEN or return ();
# Possible values for $PREV: -1=Uninitialized 0=NUMBER 1=TEXT
for (my $i = 0; $i < $LEN; $i++)
{
$TYPE = vec($_[0], $i, 8);
$TYPE = $TYPE < 48 || $TYPE > 57; # Is it a number?
if ($PREV == !$TYPE) # Same as before?
{
push(@A, substr($_[0], $PTR, $i-$PTR));
$PTR = $i;
}
$PREV = $TYPE;
}
push(@A, substr($_[0], $PTR)); # Process last chunk
return @A;
}
##################################################
This code outputs the following:
James = [40, 4, 26, 15]
John = [35, 31]
Pete = []
Bob = []
|