2008-11-21 7 views
1

J'ai un problème avec un script Perl. Il modifie le contenu d'un fichier, puis le rouvre pour l'écrire et, dans le processus, certains caractères sont perdus. Tous les mots commençant par '%' sont supprimés du fichier. C'est assez ennuyeux car les expressions% sont des espaces réservés variables pour les boîtes de dialogue.Pourquoi mon script Perl supprime-t-il des caractères du fichier?

Avez-vous une idée pourquoi? Le fichier source est un fichier XML avec encodage par défaut

Voici le code:

undef $/; 
open F, $file or die "cannot open file $file\n"; 
my $content = <F>;           
close F;              

$content =~s{status=["'][\w ]*["']\s*}{}gi; 

printf $content; 

open F, ">$file" or die "cannot reopen $file\n";    
printf F $content;           
close F or die "cannot close file $file\n"; 

Répondre

26

Vous utilisez là printf et il pense que son premier argument est une chaîne de format. Voir le printf documentation pour plus de détails. Quand je rencontre ce genre de problème, je m'assure toujours que j'utilise correctement les fonctions. :)

Vous voulez probablement print:

print FILE $content; 

Dans votre exemple, vous n'avez pas besoin de lire dans le fichier entier depuis votre substitution ne traversent pas les lignes. Au lieu d'essayer de lire et écrire dans le même fichier à la fois, utilisez un fichier temporaire:

open my($in), "<", $file  or die "cannot open file $file\n"; 
open my($out), ">", "$file.bak" or die "cannot open file $file.bak\n"; 

while(<$in>) 
    { 
    s{status=["'][\w ]*["']\s*}{}gi; 
    print $out; 
    } 

rename "$file.bak", $file or die "Could not rename file\n"; 

Cela réduit également à ce programme en ligne de commande:

% perl -pi.bak -e 's{status=["\']\\w ]*["\']\\s*}{}g' file 
4

Er. Vous utilisez printf. Printf interprète "%" comme quelque chose de spécial.

utilisez plutôt "print".

Si vous devez utiliser printf, utilisez

printf "%s", $content; 

Note importante:

printf signifie Format d'impression, comme il le fait en C.

fprintf est le équivélant en C pour le fichier IO.

Perl n'est pas C.

Et même en C, mettre votre contenu en tant que paramètre 1 vous fait tirer dessus pour des raisons de sécurité.

0

Ou encore

perl -i bak -pe 's{status=["\'][\w ]*["\']\s*}{}gi;' yourfiles 

-e dit "il y a le code ci-dessous pour vous d'exécuter"

-i bak dit "Renommez l'ancien fichier à whatever.bak"

-p ajoute une boucle de lecture-impression autour du code -e

Les doublures Perl sont un outil puissant et peuvent vous faire économiser beaucoup de corvées.

+0

non, -i bak dit "renommer l'ancien fichier en quelquechose". quel.bak serait -i .bak – ysth

0

Si vous voulez une solution qui soit consciente de la nature XML des documents (c.-à-d., Seulement supprimer les attributs d'état, et ne correspond pas le contenu du texte), vous pouvez également utiliser XML::PYX:

$ pyx doc.xml | perl -ne'print unless /^Astatus/' | pyxw 
0

C'est parce que vous avez utilisé printf au lieu d'imprimer et vous savez printf n'imprime pas « % » (parce qu'il penserait vous oublié de taper le symbole de format tel que% s,% f etc) sauf si vous l'avez explicitement mentionné par "%%". :-)