6
votes

Lire un gros fichier et des sections de sortie correspondant à plusieurs paramètres

Je dois rarement faire face à des scripts, donc je suis contre un manque de connaissances pour ce problème.

J'ai un fichier> 500 Mo dans le texte, qui est joliment sectionné, mais je sais qu'il y en a 5 à 10 "mauvais" sections à l'intérieur. Les données des sections peuvent être évaluées assez facilement par un humain, je ne sais pas comment le faire dans un programme.

Je prends une bonne valeur connue dans #field myfield - Toutefois, si cette valeur n'apparique pas dans #field emplacement , quelque chose s'est mal passé.

Un exemple de deux sections dans le fichier ressemble à ceci. Le premier est "mauvais" et la seconde est "bonne". xxx

  1. Sections Démarrez et finillez logiquement, avec #start et #end

  2. si #field emplacement n'existe pas, allez à la section suivante

  3. si #field myfield = "bar" et #field emplacement ne contient pas bar , imprimer toutes les lignes de cette section à un nouveau fichier.

  4. Remarque - clarification de #field myfield = "bar" - Ceci est une valeur de contrôle I mis en saisissant d'autres informations sur les données car ce fichier est en construction (dans mon cas C'est un indicateur de langue, tel que FR ou DE. de sorte qu'il serait littéralement #field myfield = "fr" toute autre valeur de ce champ serait ignoré, ce n'est pas un enregistrement qui correspond à mon Critères.

    Je crois que cela peut être fait dans Awk ou Perl, je peux faire des doublures très simples, mais cela dépasse mes compétences.


4 commentaires

Les sections sont-elles séparées par les nouvelles lignes ou sont-elles l'une après l'autre?


Votre "bonne section" veut-elle avoir une double devis entre "Emplacement =" et "http:"?


Alors qu'est-ce qui fait précisément la mauvaise section? valeur = foo dans l'URL vs. bar dans le myfield ? (et est-il censé être une citation avant le http dans la bonne section?)


Kevin - Le "mauvais" est exactement ça, j'ai une bonne valeur connue dans Myfield, et si cette valeur ne s'est pas présentée dans la chaîne de localisation, quelque chose s'est mal passé.


4 Réponses :


2
votes

Vous pouvez faire quelque chose comme ci-dessous. C'est juste un brouillon, mais cela fonctionnera avec vos échantillons de données. Utilisez opérateur de bascule pour trouver le début et la fin des enregistrements. Utilisez un hachage pour stocker les valeurs de champ et une matrice pour stocker l'enregistrement.

Je vérifie simplement si la valeur est dans la chaîne d'emplacement, vous pouvez souhaiter réduire davantage la vérification en vous assurant qu'il est dans le bon endroit ou le bon cas. P>

use strict;
use warnings;

my @record;
my %f;
while(<DATA>) {
    if (/^#START / .. /^#END */) {
        if (/^#START /) {
            @record = (); # reset
            %f = ();
        }
        push @record, $_;
        if (/^#END */) { # check and print
            if ($f{'LOCATION'} !~ /$f{'MyField'}/) {
                print @record; 
            }
        } else {         # add fields to hash
            if (/^#FIELD (.+)/) {
                            # use split with limit of 2 fields
                my ($key, $val) = split /=/, $1, 2;
                next unless $val; # no empty values
                $val =~ s/^"|"$//g; # strip quotes
                $f{$key} = $val;
            }
        }
    }
}

__DATA__
#START Descriptor
#FIELD LOCATION="http://path.to/file/here&Value=FOO&OtherValue=BLAH"
#FIELD AnythingElse
#FIELD MyField="BAR"
#END
#START Descriptor
#FIELD LOCATION=http://path.to/file/here&Value=BAR&OtherValue=BLAH"
#FIELD AnythingElse
#FIELD MyField="BAR"
#END


1 commentaires

C'était bien commenté et utile pour moi comme le questionneur. C'est très cool que j'ai à la fois une réponse "courte" et une réponse "longue". Merci! (Je joue avec ces suggestions maintenant!)



2
votes

one-liner:

perl -ne 'BEGIN { $/ = "#END\n" }' -e '/MyField="(.*?)"/; print if !/Value=$1/' <file >newfile


2 commentaires

Imprimer $ _ n'est pas nécessaire, $ _ est la variable par défaut, impression devrait suffire


Fichier> Newfile fonctionnerait aussi bien que Newfile . En fait, cela fonctionne mieux comme $ argv obtenir au nom du fichier d'entrée.



0
votes

Set Séparateur d'enregistrement d'entrée sur #end \ n et lire directement des enregistrements: xxx


1 commentaires

Dans le 2e enregistrement, où Myfield = bar et emplacement comprennent une barre, c'est un enregistrement OK, mes opérations ont réussi. L'enregistrement préalable, où la barre n'apparaît pas à l'emplacement était l'erreur. Il me dit que j'avais un problème pour analyser le fichier à cet endroit. Je veux seulement lire les segments qui ont eu un problème.



2
votes

Voici un petit gawk code> one-liner pour vous -

[jaypal:~/Temp] gawk '
{
    if ($2!~/^#FIELD LOCATION/)
    {
        next;
    }
    else
    {
        split($2,ary,"=|&");
        split($4,ary1,"=|\"");
        if(ary[4]!=ary1[3])
            {
                print $0 > "badrec.file"
            }
    }
}' RS="#END\n" ORS="#END\n" FS="\n" file

[jaypal:~/Temp] cat badrec.file 
#START Descriptor # Bad Record
#FIELD LOCATION="http://path.to/file/here&Value=FOO&OtherValue=BLAH"
#FIELD AnythingElse
#FIELD MyField="BAR"
#END


0 commentaires