0
votes

Besoin d'ouvrir un fichier et de remplacer plusieurs chaînes

J'ai un très gros fichier XML. Il a certain d'incrémenter des nombres à l'intérieur, que je voudrais remplacer par un autre numéro d'incrémentation différent. J'ai regardé et voici ce que quelqu'un a suggéré ici avant. Malheureusement, je ne peux pas le faire fonctionner: (

Dans le code ci-dessous, toutes les instances de 40960 devraient être remplacées par 41984, toutes les instances de 40961 avec 41985 avec 41985, etc. Ce que je fais mal? P>

use strict;
use warnings;

my $old = 40960;
my $new = 41984;
my $string;

my $file = 'file.txt';

rename($file, $file.'.bak');
open(IN, '<'.$file.'.bak') or die $!;
open(OUT, '>'.$file) or die $!;

$old++;
$new++;

for (my $i = 0; $i < 42; $i++) {
    while(<IN>) {
        $_ =~ s/$old/$new/g;
        print OUT $_;
    }
}

close(IN);
close(OUT);


1 commentaires

Vous devrez peut-être rechercher au début du fichier d'entrée pour chaque itération dans la boucle pour , voir Perldoc recherche . Mais il pourrait y avoir des approches plus efficaces qui vous permet de remplacer tous les chiffres à la fois


3 Réponses :


0
votes

Voici une solution alternative qui lit le fichier d'entrée dans une chaîne et effectue toutes les substitutions à la fois: xxx

Remarque: peut probablement être rendue plus efficace en utilisant REGEXP :: Assemblez


1 commentaires

Mon fichier XML est assez gros, je me demande si cela provoquerait un problème si converti sur une chaîne.



1
votes

Voici un exemple qui fonctionne en ligne par ligne, de sorte que la taille du fichier est immatérielle. L'exemple suppose que vous voulez remplacer les choses comme "45678", mais pas "Fred45678". L'exemple suppose également qu'il existe une gamme de nombres, et vous les souhaitez remplacer par une nouvelle gamme décalée par une constante. xxx

invoqué avec le fichier que vous souhaitez transformer en tant qu'agent, il produit une sortie modifiée sur stdout. Avec l'entrée suivante ... xxx

... il produit cette sortie. xxx

Il y a un couple de Les pérlismes classiques ici, mais l'exemple ne devrait pas être difficile de suivre si vous RTFM de manière appropriée.


2 commentaires

Cela semble intéressant, mais aussi assez complexe pour un débutant total comme moi. Pourriez-vous ajouter quelques commentaires sur ce que fait quoi?


REPL () est une fonction simple qui, donnée x, retourne x + diffff si x> = min et x <= max, ou retourne simplement x sinon. La boucle principale () la boucle iTère sur des lignes du fichier entrant, localise toute séquence numérique entourée de conditions "limites" (c'est la partie \ B de la regex), remplace ces chaînes avec la fonction REPLE () renvoie et imprime la ligne modifiée. Si un numéro tombe en dehors de la plage min-max, le nombre est simplement substitué par lui-même, il n'y a donc aucun changement. Si le nombre tombe dans la plage min-max, toutefois, la substitution remplace l'ancien numéro avec un nouveau.



1
votes

Autres réponses Vous donne de meilleures solutions à votre problème. Le mien se concentre sur l'explication de la raison pour laquelle votre code n'a pas fonctionné.

Le noyau de votre code est ici: p> xxx pré>

vous incrémentez les valeurs de old Code> et $ neuf code> en dehors de vos boucles. Et vous ne changez jamais ces valeurs à nouveau. Donc, vous ne faites que la même substitution (changeant 40961 à 41985) 42 fois. Vous n'essayez jamais de changer d'autre chiffres. P>

Aussi, regardez le pendant code> boucle qui se lit à partir de dans code>. Sur votre première itération (lorsque $ i code> est 0) Vous lisez toutes les données de dans code> et le pointeur de fichier reste à la fin du fichier. Ainsi, lorsque vous allez dans le pendant code> à nouveau sur votre deuxième itération (et toutes les itérations suivantes), vous ne lisez aucune donnée du tout dans le fichier. Vous devez réinitialiser le pointeur de fichier au début de votre fichier à la fin de chaque itération. P>

OH, et la logique de base est fausse. Si vous y réfléchissez, vous allez finir par écrire chaque ligne au fichier de sortie 42 fois. Vous devez faire toutes les substitutions possibles avant d'écrire la ligne. Donc, votre boucle interne doit être la boucle extérieure (et vice-versa). P>

Mettre ces suggestions ensemble, vous avez besoin de quelque chose comme ceci: p>

my $old    = 40960;
my $change = 1024;

while (<IN>) {
    # Easier way to write your loop
    for my $i ( 1 .. 42 ) {
        my $new = $old + $change;
        # Use \b to mark word boundaries
        s/\b$old\b/$new/g;
        $old++;
    }
    # Print each output line only once
    print OUT $_;
}


1 commentaires

Merci, je me suis rendu compte de savoir comment j'ai échoué avec le placement en boucle, mais j'ai complètement manqué le problème de la poignée de fichier.