use strict;
use warnings;
use Text::Balanced 'extract_bracketed';
my $string = q/the users contain (bbc (333)) BLAH BLAH (ddc (223)) BLA
+H BLAH(ccc (123))/;
while( length $string ) {
my( $name, $id, $rest ) = extract_record($string);
print "Name: $name, ID: $id\n";
$string = $rest;
}
sub extract_record {
my $string = shift;
my( $unwanted, $wanted, $rest ) = extract($string);
return (extract($wanted))[0,1], $rest;
}
sub extract {
my $input = shift;
my( $balanced, $rest, $prefix ) = extract_bracketed($input, '()',
+qr/[^(]*/);
$balanced =~ s/^\(|\)$//g if length $balanced;
return map { trim($_) } $prefix, $balanced, $rest;
}
sub trim {
my $string = shift;
$string =~ s/^\s+|\s+$//g;
return $string;
}
Regexp::Common has Regexp::Common::balanced which would probably facilitate a reasonably robust and possibly less complicated solution (left as an exercise for the reader, as I've lost interest at this point. ;)
Update: But a pure-regexp approach would work for data that is relatively simple, as the OP's data seems to be:
my $string = q/the users contain (bbc (333)) BLAH BLAH (ddc (223)) BLA
+H BLAH(ccc (123))/;
my $re = qr/
\( (?<name> [^(]+ ) # Capture name.
\( (?<id> [^)]+ ) # Capture ID.
\)\) # Closing parens.
/x;
print "Name: $+{name}, ID: $+{id}\n" while $string =~ m/$re/g;
...which is pretty much back to what you started with. ;)
|