Question

Mon fichier d'entrée est comme ci-dessous:

HEADER 
{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}

{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}

{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}

{ABC|*|XYZ:ghi:jkl {JKL 0 372 0} {{Points {}}}}

{ABC|*|XYZ:mno:pqr {GHI 0 34 0} {{Points {}}}}

{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }
TRAILER

Je veux extraire le fichier dans un tableau comme ci-dessous:

$array[0] = "{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}"

$array[1] = "{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}"

$array[2] = "{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}"

..
..

$array[5] = "{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }"

Ce qui signifie, je dois correspondre à la première ouverture accolade avec son accolade fermante et extraire la chaîne entre les deux.

J'ai vérifié le lien ci-dessous, mais cela ne laissera pas à ma question. Regex pour obtenir la chaîne entre accolades « {Je veux ce qui est entre les accolades} »

Je suis en train, mais pourrait vraiment aider si quelqu'un peut me aider à leur savoir-faire ...

Merci Sri ...

Était-ce utile?

La solution

Cela peut certainement être fait avec regex au moins dans les versions modernes de Perl:

my @array = $str =~ /( \{ (?: [^{}]* | (?0) )* \} )/xg;

print join "\n" => @array;

L'expression régulière correspond à un bloc d'accolade qui contient soit des caractères d'entretoise non bouclé, ou une récursion en lui-même (correspond accolades imbriquées)

Edit: le code ci-dessus fonctionne en Perl 5.10+, pour les versions antérieures, la récursion est un peu plus bavard:

my $re; $re = qr/ \{ (?: [^{}]* | (??{$re}) )* \} /x;

my @array = $str =~ /$re/xg;

Autres conseils

Utilisez

Je deuxième suggestion de ysth d'utiliser le Text::Balanced module. Quelques lignes vous sur votre chemin.

use strict;
use warnings;
use Text::Balanced qw/extract_multiple extract_bracketed/;

my $file;
open my $fileHandle, '<', 'file.txt';

{ 
  local $/ = undef; # or use File::Slurp
  $file = <$fileHandle>;
}

close $fileHandle;

my @array = extract_multiple(
                               $file,
                               [ sub{extract_bracketed($_[0], '{}')},],
                               undef,
                               1
                            );

print $_,"\n" foreach @array;

SORTIE

{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}
{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}
{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}
{ABC|*|XYZ:ghi:jkl {JKL 0 372 0} {{Points {}}}}
{ABC|*|XYZ:mno:pqr {GHI 0 34 0} {{Points {}}}}
{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }

Vous pouvez toujours compter les accolades:

my $depth = 0;
my $out = "";
my @list=();
foreach my $fr (split(/([{}])/,$data)) {
    $out .= $fr;
    if($fr eq '{') {
        $depth ++;
    }
    elsif($fr eq '}') {
        $depth --;
        if($depth ==0) {
            $out =~ s/^.*?({.*}).*$/$1/s; # trim
            push @list, $out;
            $out = "";
        }
    }
}
print join("\n==================\n",@list);

est vieux, plaine de style Perl (et laid, probablement).

Je ne pense pas que pures expressions régulières sont ce que vous voulez utiliser ici (à mon humble avis cela pourrait ne pas être encore analysable utilisant l'expression rationnelle).

Au lieu de cela, construire un petit analyseur, similaire à ce qui est montré ici: http: //www.perlmonks .org /? node_id = 308039  (Voir la réponse par shotgunefx (Parson) le 18 nov 2003 à 18h29 UTC)

UPDATE Il semble que ce pourrait être faisable avec une expression régulière - j'ai vu une référence à la correspondance entre parenthèses imbriquées dans maîtrise des expressions rationnelles (qui est disponible sur Google Livres et peuvent donc être googlé car si vous n'avez pas le livre - voir le chapitre 5, section « Assemblez des parenthèses équilibré »)

Vous êtes beaucoup mieux en utilisant une machine d'état d'un regex pour ce type d'analyse syntaxique.

Les expressions régulières sont en fait assez mauvais pour accolades correspondant. Selon la profondeur que vous voulez aller, vous pouvez écrire une grammaire complète (ce qui est beaucoup plus facile que ça!) Pour Parse :: RecDescent . Ou, si vous voulez juste pour obtenir les blocs, la recherche par le biais de l'ouverture « { » marques et la fermeture « } », et juste garder le compte du nombre sont ouverts à tout moment.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top