2017-01-31 4 views
0

J'ai été en mesure d'utiliser flip-flop pour extraire le texte dans le passé où j'ai différents START & END. Cette fois, j'ai eu beaucoup de mal à essayer d'extraire du texte parce que je n'ai pas de délimiteurs différents dans mon fichier source, car START & END de la bascule sont les mêmes. Je veux que le flip-flop commence à vrai quand les êtres de ligne avec l'année aaaa & continuent à pousser $_ à un tableau jusqu'à ce qu'une autre ligne commence aaaa. Le problème avec la bascule est qu'elle sera alors fausse sur mon prochain START. L'utilisation de ce qui précède pour les données source données manquera la deuxième partie multi-ligne du fichier que je dois également faire correspondre. Peut-être que le flip-flop que je pensais être la meilleure façon d'analyser un fichier multi-lignes ne fonctionnera pas dans ce cas? Ce que je veux faire est de commencer à faire correspondre avec la première ligne commençant par la date & continuer à correspondre jusqu'à la ligne avant la ligne suivante commençant par une date.perl extrait du texte entre SAME délimiteur en utilisant flip-flop

données de l'échantillon est:

2017 message 1 
Text 
Text 

Text 

2017 message 2 
more text 
more text 

more text 

2017 message 3 
yet more text 
yet more text 

yet more text 

mais je reçois:

2017 message 1 
Text 
Text 

Text 

2017 message 2 
2017 message 3 
yet more text 
yet more text 

yet more text 

... message manquant 2 contenu ..

Je ne peux pas compter sur l'espace ou un autre séparateur END dans mes données source. Ce que je voulais, c'était que chaque message soit imprimé (en fait, push @myarray, $_ & puis testez les correspondances), mais ici il me manque des lignes sous le message 2 parce que la bascule est réglée sur faux. N'importe quelle manière de manipuler ceci avec la bascule ou je dois employer autre chose? Merci d'avance pour toute personne qui peut aider/conseiller.

Répondre

1

Je ne sais pas comment le faire avec flipflop. Je l'ai essayé avant un an. Mais la même chose que j'ai fait avec une certaine logique.

my $line_concat; 
my $f = 0; 
while (<DATA>) { 
    if(/^2017/ && !$f) { 
     $f = 1; 
    } 

    if (/^2017/) { 
     print "$line_concat\n" if $line_concat ne ""; 
     $line_concat = ""; 
    } 

    $line_concat .= $_ if $f; 
} 

print $line_concat if $line_concat ne ""; 
+0

@simbabque Merci mon ami. Post édité. – mkHun

+0

Encore une chose ... ça marche, mais vous ne réinitialisez jamais '$ f'. Pourquoi pas? Vous pouvez mettre la réinitialisation et un 'refaire 'dans le second bloc' if' pour que chaque paire soit réellement une paire, mais je ne vois pas d'avantage à le faire. – simbabque

2

Voici un chemin à parcourir:

use Modern::Perl; 
use Data::Dumper; 
my $part = -1; 
my $parts; 
while(<DATA>) { 
    chomp; 
    if (/^2017/ .. 1==0) { 
     $part++ if /^2017/; 
     push @{$parts->[$part]}, $_; 
    } 
} 
say Dumper$parts; 

__DATA__ 
2017 message 1 
Text 
Text 

Text 

2017 message 2 
more text 
more text 

more text 

2017 message 3 
yet more text 
yet more text 

yet more text 

Sortie:

$VAR1 = [ 
      [ 
      '2017 message 1', 
      'Text', 
      'Text', 
      '', 
      'Text', 
      '' 
      ], 
      [ 
      '2017 message 2', 
      'more text', 
      'more text', 
      '', 
      'more text', 
      '' 
      ], 
      [ 
      '2017 message 3', 
      'yet more text', 
      'yet more text', 
      '', 
      'yet more text' 
      ] 
     ]; 
+0

Hmm, bien repéré. Cette ligne 'if' est en réalité redondante n'est-ce pas? – Sobrique

+1

@Sobrique, Il est utilisé pour sauter les lignes avant le premier correspondant '/^2017 /'. – ikegami

1

Flip Flop avec un séparateur adapté ne fonctionne pas bien trop, comme vous l'avez trouvé .

Avez-vous considéré le réglage $/ à la place?

.: par exemple

#!/usr/bin/env perl 
use strict; 
use warnings; 

local $/ = "2017 message"; 
my $count; 

while (<DATA>) { 

    print "\nStart of block:", ++$count, "\n"; 

    print; 

    print "\nEnd of block:", $count, "\n"; 
} 

__DATA__ 
2017 message 1 
Text 
Text 

Text 

2017 message 2 
more text 
more text 

more text 

2017 message 3 
yet more text 
yet more text 

yet more text 

Bien que ce n'est pas parfait, car il divise le fichier sur le delimiter - ce qui signifie qu'il ya un « bit » avant le premier (vous obtenez 4 morceaux). Vous pouvez resplice avec une utilisation judicieuse des Chomp », qui supprime $/ du morceau en cours:

#!/usr/bin/env perl 
use strict; 
use warnings; 

local $/ = "2017 message"; 
my $count; 

while (<DATA>) { 
    #remove '2017 message' 
    chomp; 
    #check for empty (first) block 
    next unless /\S/; 
    print "\nStart of block:", ++$count, "\n"; 
    #re add '2017 message' 
    print $/; 
    print; 

    print "\nEnd of block:", $count, "\n"; 
} 

Sinon, que diriez-vous d'un tableau de tableaux, que vous mettez à jour la« clé cible chaque fois que vous frappez un message ?

#!/usr/bin/env perl 
use strict; 
use warnings; 

use Data::Dumper; 

my %messages; 
my $message_id; 
while (<DATA>) { 
    chomp; 
    if (m/2017 message (\d+)/) { $message_id = $1 }; 
    push @{ $messages{$message_id} }, $_; 
} 

print Dumper \%messages; 

Remarque - J'utilise un hachage, pas un tableau, car c'est un peu plus robuste pour le séquençage des messages qui ne démarre pas consécutivement à partir de zéro. (Et array utilisant cette approche aurait un élément 'zeroth' vide).

Remarque - il aura également '' 'vide' pour les lignes vides. Vous pouvez les filtrer si vous le souhaitez.

1

Vous avez juste besoin d'un tampon qui accumule les lignes jusqu'à ce que vous trouviez un /^20\d\d[ ]/ correspondant ou la fin du fichier.

my $in = 0; 
my @buf; 
while (<>) { 
    if ($in && /^20\d\d[ ]/) { 
     process(@buf); 
     @buf =(); 
     $in = 0; 
    } 

    push @buf, $_ if $in ||= /^2017[ ]/; 
} 

process(@buf) if $in; 

Nous pouvons réorganiser le code pour faire en sorte que les dossiers sont traités en un seul endroit, ce qui permet process à inline.

my $in = 0; 
my @buf; 
while (1) { 
    $_ = <>; 

    if ($in && (!defined($_) || /^20\d\d[ ]/)) { 
     process(@buf); 
     @buf =(); 
     $in = 0; 
    } 

    last if !defined($_); 

    push @buf, $_ if $in ||= /^2017[ ]/; 
} 
+0

Les commentaires ci-dessus n'ont jamais été corrects et ont été rendus obsolètes par les changements apportés à la réponse. – ikegami