title: Football team: Real Madrid stadium: Santiago Bernabeu players: Zinédine Zidane, Ronaldo, Luís Figo, Roberto Carlos, Raúl personnel: José Mourinho (head coach)
Contrary to what many are saying in their answers, you do not need lookahead (other than the Regex's own), you would only need to capture part of the delimiter, like so:
my @hash_fields = grep { length; } split /\s*(\w+):\s*/;
My full solution below:
my %handlers
= ( players => sub { return [ grep { length; } split /\s*,\s*/, shift ]; }
, personnel => sub {
my $value = shift;
my %personnel;
# Using recursive regex for nested parens
while ( $value =~ m/([^(]*)([(](?:[^()]+|(?2))*[)])/g ) {
my ( $name, $role ) = ( $1, $2 );
$role =~ s/^\s*[(]\s*//;
$role =~ s/\s*[)]\s*$//;
$name =~ s/^\s+//;
$name =~ s/\s+$//;
$personnel{ $role } = $name;
}
return \%personnel;
}
);
my %hash = grep { length; } split /(?:^|\s+)(\w+):\s+/, <DATA>;
foreach my $field ( keys %handlers ) {
$hash{ $field } = $handlers{ $field }->( $hash{ $field } );
}
Dump looks like this:
%hash: {
personnel => {
'assistant coach (es)' => 'Aitor Karanka',
'head coach' => 'José Mourinho'
},
players => [
'Zinédine Zidane',
'Ronaldo',
'Luís Figo',
'Roberto Carlos',
'Raúl'
],
stadium => 'Santiago Bernabeu',
team => 'Real Madrid',
title => 'Football'
}
This should do it. line.txt contains "title: Football team: Real Madrid stadium: Santiago Bernabeu players: Zinédine Zidane, Ronaldo, Luís Figo, Roberto Carlos, Raúl personnel: José Mourinho (head coach) Aitor Karanka (assistant coach (es))"
#!/usr/bin/perl
use strict;
use warnings;
my $fn="./line.txt";
open(IN,$fn);
my @lines=<IN>;
my %hash;
my $hashKey;
foreach my $line (@lines){
$line=~s/\n//g;
my @split1=split(" +",$line);
foreach my $split (@split1){
if($split=~m/:$/){
$hashKey=$split;
}else{
if(defined($hash{$hashKey})){
$hash{$hashKey}=$hash{$hashKey}.$split." ";
}else{
$hash{$hashKey}=$split." ";
}
}
}
}
close(IN);
foreach my $key (keys %hash){
print $key.":".$hash{$key}."\n";
}
Use a lookahead assertion:
say for split /(?=\w+:)/, $real_madrid_string;
Output
title: Football
team: Real Madrid
stadium: Santiago Bernabeu
players: Zinédine Zidane Ronaldo Luís Figo Roberto Carlos Raúl
personnel: José Mourinho (head coach) Aitor Karanka (assistant coach (es))
The best way is to use the split
command using a zero-width lookahead:
$string = "title: Football team: Real Madrid stadium: Santiago Bernabeu players: Zinédine Zidane, Ronaldo, Luís Figo, Roberto Carlos, Raúl personnel: José Mourinho (head coach) Aitor Karanka (assistant coach (es))";
@split_string = split /(?=\b\w+:)/, $string;
$string = "title: Football team: Real Madrid stadium: Santiago Bernabeu players: Zinédine Zidane, Ronaldo, Luís Figo, Roberto Carlos, Raúl personnel: José Mourinho (head coach) Aitor Karanka (assistant coach (es))";
@words = split(' ', $string);
@lines = undef;
@line = shift(@words);
foreach $word (@words)
{
if ($word =~ /:/)
{
push(@lines, join(' ', @line));
@line = undef;
}
else
{
push(@line, $word);
}
}
print join("\n", @lines);