88 votes

Recherche et remplacement multiligne avec Perl

Je sais que ce genre de questions a déjà été posé de nombreuses fois auparavant. La raison pour laquelle je reviens ici est que j'ai l'impression d'avoir manqué quelque chose de simple et de fondamental.

Est-il possible d'améliorer ce type de routine de recherche et de remplacement ? Par exemple, sans ouvrir deux fois le même fichier. Les conseils en matière de vitesse sont également les bienvenus.

Veuillez noter que cela fonctionne avec les correspondances multilignes et remplace également les chaînes multilignes.

#!/bin/perl -w -0777

local $/ = undef;

open INFILE, $full_file_path or die "Could not open file. $!";
$string =  <INFILE>;
close INFILE;

$string =~ s/START.*STOP/$replace_string/sm;

open OUTFILE, ">", $full_file_path or die "Could not open file. $!";
print OUTFILE ($string);
close OUTFILE;

0 votes

Il semble que vous essayez d'éditer le fichier sur place. C'est-à-dire de l'ouvrir en lecture et en écriture. Est-ce correct ?

0 votes

Oui, l'édition de fichiers sur place. C'est le cas le plus courant pour moi.

0 votes

Je gravite autour des solutions générales, mais j'ai parfois besoin qu'on me rappelle que pour quelque chose comme ça, il peut être (et c'était le cas aujourd'hui !) intéressant d'essayer dans un IDE (par exemple, Find In Project + Find-and-Replace d'IntellJ) par rapport à la montée en puissance, aux essais et erreurs, et à la vérification après coup pour une solution de script.

114voto

aks Points 3315

Ce type de recherche et de remplacement peut être réalisé avec une ligne unique telle que -.

perl -i -pe 's/START.*STOP/replace_string/g' file_to_change

Pour d'autres façons d'accomplir la même chose, consultez cette page. filetage . Pour gérer les recherches multi-lignes, utilisez la commande suivante -

perl -i -pe 'BEGIN{undef $/;} s/START.*STOP/replace_string/smg' file_to_change

Afin de convertir le code suivant d'un one-liner en un programme perl, jetez un coup d'œil à l'interface suivante documentation de perlrun .

Si vous ressentez vraiment le besoin de convertir ceci en un programme fonctionnel, laissez Perl gérer l'ouverture/la fermeture des fichiers pour vous.

#!/usr/bin/perl -pi
#multi-line in place substitute - subs.pl
use strict;
use warnings;

BEGIN {undef $/;}

s/START.*STOP/replace_string/smg;

Vous pouvez alors appeler le script avec le nom du fichier comme premier argument

$perl subs.pl file_to_change

Si vous voulez un script plus consistant où vous devez gérer les opérations d'ouverture/fermeture de fichiers (n'aimons nous pas toutes ces déclarations 'die') alors jetez un coup d'oeil à l'exemple dans perlrun avec le commutateur -i[extension].

0 votes

Comment convertir ce texte en un véritable code perl ? Est-ce que ça devient moche ?

1 votes

Vérifiez l'édition, le bloc BEGIN garantit maintenant que cela fonctionne également sur les correspondances multi-lignes.

1 votes

D'accord, est-ce que ça peut être écrit en code perl (pas en one-liner) ? Je veux savoir ce qu'il advient des routines d'ouverture/écriture de fichiers.

100voto

Beejor Points 3677

J'ai extrait la réponse courte des commentaires, pour tous ceux qui cherchent une réponse rapide, et la raison pour laquelle Perl ignore les options RegEx de la ligne de commande.

perl -0pe 's/search/replace/gms' file

Sans le -0 Perl traite les données ligne par ligne ce qui fait échouer les recherches multilignes.

2voto

Nathan Fellman Points 31310

En considérant que tu engloutis tout le contenu du dossier avec :

local $/ = undef;

open INFILE, $full_file_path or die "Could not open file. $!";
$string =  <INFILE>;
close INFILE;

Et ensuite faire tout le traitement avec $string il n'y a pas de lien entre la façon dont vous manipulez le fichier et la façon dont vous traitez son contenu. Vous auriez un problème si vous ouvriez le fichier pour l'écrire avant d'avoir fini de le lire, car l'ouverture d'un fichier pour l'écrire crée un nouveau fichier, en supprimant le contenu précédent.

Si tout ce que vous essayez de faire est d'économiser sur les déclarations d'ouverture/fermeture, alors faites comme suit Jonathan Leffer a suggéré . Si votre question porte sur la recherche et le remplacement multilignes, veuillez préciser quel est le problème.

0 votes

Il s'agit d'une recherche et d'un remplacement génériques multilignes. Est-il vraiment normal que j'ouvre à nouveau le même pointeur de fichier, même si le fichier est très volumineux ? Dans les expressions à une ligne, il ne semble pas nécessaire d'ouvrir deux fois le même fichier. Quelque chose m'échappe encore. Je devrais peut-être mettre en pratique l'exemple de Jonathan.

0 votes

La création d'un gestionnaire de fichier n'a rien à voir avec la taille du fichier. Il s'agit simplement d'un pointeur. L'acte d'ouvrir un fichier n'implique pas la lecture de son contenu.

0 votes

Je pense qu'il s'agit là de mon incompréhension. Comment ouvrir le même fichier une seule fois pour la lecture et l'écriture alors que la lecture implique l'opération nécessaire de le parcourir pour trouver des correspondances possibles ?

1voto

Sinan Ünür Points 76179

Si vous allez slurp le dossier, je recommande Fichier::Slurp .

#!/usr/bin/perl

use strict;
use warnings;

my $file_contents = read_file $full_file_path;

# As far as I can see, you do not use the m switch
$file_contents =~ s/START.*STOP/$replace_string/s;

write_file $full_file_path, $file_contents;

__END__

read_file y write_file sera croak quand quelque chose va mal.

0voto

Tilo Points 13833

Vous pourriez vouloir vérifier mon Perl script, qui est testé à la bataille (utilisé fortement en production), et a beaucoup de fonctionnalités, telles que :

  • effectuer des opérations multiples de recherche-remplacement ou de requête-recherche-remplacement
  • les expressions de recherche et de remplacement peuvent être données sur la ligne de commande ou lues à partir d'un fichier traite plusieurs fichiers d'entrée
  • descendre récursivement dans le répertoire et effectuer de multiples opérations de recherche/remplacement sur tous les fichiers
  • les expressions perl définies par l'utilisateur sont appliquées à chaque ligne de chaque fichier d'entrée exécution facultative en mode paragraphe (pour la recherche/remplacement de plusieurs lignes)
  • mode interactif
  • mode batch
  • éventuellement, les fichiers de sauvegarde et la numérotation des sauvegardes
  • préserver les modes/propriétaire lorsqu'il est exécuté en tant que Root
  • ignore les liens symboliques, les fichiers vides, les fichiers protégés en écriture, les sockets, les pipes nommés, et les noms de répertoire
  • remplacer optionnellement les lignes ne correspondant que / ne correspondant pas à une expression régulière donnée

https://github.com/tilo/replace_string

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X