10
votes

Dans Perl, comment est-ce que je "slurp" le contenu de plusieurs fichiers dans une chaîne?

Perl a beaucoup d'idiomes pratiques pour faire des choses communes facilement, notamment:

  1. L'opérateur de lecture de fichiers code>, s'il est utilisé sans fichierHandle, ouvrira de manière transparente et lit tous les fichiers dans @argv code>, une ligne à un TEMPS: P> XXX PRE> LI>

  2. par (localement) réinitialisation du séparateur d'enregistrement d'entrée $ / code>, je peux "slurp" tout un fichier entier à la fois: p> XXX PRE> LI> ol>

    Mais ces deux idioms ne fonctionnent pas assez bien ensemble, car je m'attendais: après avoir réinitialisé $ / code>, slurping avec code> s'arrête à la fin de Fichier: Ce qui suit me donne le contenu du premier fichier uniquement. P>

    local $/; $content = <>;
    


5 commentaires

mon @Content = do {local $ /; <>}; si cela ne vous dérange pas de récupérer des fichiers dans un tableau (pas de jointure ou de chaîne Concat nécessaire).


Dupliqué possible de Fichier de fantaisie Slurping à Perl .


Qu'avez-vous fait pour vous assurer que cette question n'est pas une duplication?


@Petermortensen, ce n'est pas un duplicata. Cette question slurpe chaque fichier dans une chaîne distincte, qui aurait alors besoin d'être jointes ensemble . Cela devra faire s'il n'y a pas de meilleure solution (c'est efficacement ce que je fais dans ma réponse de soi), mais je ne peux pas savoir que sans demander cette question .


@ Сухой27, je préfère ne pas récupérer chaque fichier dans une chaîne différente si je peux l'éviter. Ils devront être rejoints ou autrement post-traités.


3 Réponses :


10
votes

Vous réalisez que vous ne masquez que de multiples Ouvrir les appels , non? Il n'y a pas de moyen magique de lire plusieurs fichiers sans les ouvrir une par une par une

Comme vous l'avez trouvé, Perl arrêtera de lire à la fin de chaque fichier si $ / est défini sur UNDEF

Le mécanisme interne qui gère <> supprime chaque nom de fichier à partir de @argv tel qu'il est ouvert, donc je vous suggère que vous Utilisez simplement un pendant la boucle qui lit à l'aide de <> jusqu'à ce que @argv est vide

Ça ressemblerait à ce xxx


5 commentaires

Je suis juste errer. Combien de données une variable locale peut-elle tenir à Perl? Y a-t-il une limite de mémoire?


@Arijit: Un scalaire unique peut contenir autant de mémoire que le processus peut allouer, avec quelques frais généraux pour la structure de données scalaire PERL et, évidemment, l'interpréteur PERL, le programme compilé et toute autre donnée. Une corde de 2 Go est parfaitement réalisable. Il est clair que 64 bits construit de Perl pourront aborder beaucoup plus de mémoire qu'une construction 32 bits


Merci @borodin - Que se passera-t-il si la taille du fichier plus qu'un processeur peut gérer. Est-ce qu'il arrête ou saute la mémoire supplémentaire?


De quoi s'agit-il vraiment? Je pense que vous devez poser une bonne question si vous êtes intéressé. Si Perl ne peut pas affecter la mémoire dont il a besoin, il mourra avec un code de sortie non nul et le message "hors de mémoire!" . Mais vous devriez vraiment lire des fichiers dans des unités plus petites, généralement une seule ligne. Si vous pensez avoir besoin d'un fichier entier en mémoire, votre conception est probablement fausse


@Borodin, oui je me rends compte que plusieurs Ouvrir s sont impliqués. C'est ce que je voulais dire par "de manière transparente": cela se produit, mais je n'ai pas à tenir sa main ni même à le regarder.



8
votes

Comme il ne semble pas y avoir un moyen de slurper tout à la fois, une solution compacte serait de placer code> dans la liste contextuelle. Les appels répétés implicites vont tout chercher.

local $/;
$data = join "", <>;


8 commentaires

Cela tiendra tout le contenu des fichiers dans une liste jusqu'à ce qu'ils aient été lus avant de les copier sur $ données et de jeter les chaînes individuelles, il y a donc peu de point dans la modification du changement $ / < / code> en premier lieu. C'est bon s'il n'y a que quelques fichiers, mais s'il y en a de nombreuses (par exemple, en fournissant un modèle de caractères génériques comme paramètre de ligne de commande), il est gaspillé.


Perl n'a pas de comportement itérateur dans un contexte de liste? J'aurais attendu <> à pomper en interne par rejoindre , ce qui en ferait cela au pire équivalent à la boucle explicite de votre réponse (et éventuellement mieux car les cordes sont jointes intérieurement.)


Il n'y a pas de comportement caché d'itérateur à Perl, et simplement parce que Python (parfois) le fait, cela ne fait pas la de droite . Il serait tout à fait possible d'écrire un itératif et rejoindre qui effectue la façon dont vous décrivez, mais le résultat serait plus arcanique et plus lentement que les utilisations répétées de . = . La philosophie Perl est très sur la transparence, alors seules des choses comme l'algorithme de tri sont en boîte noire. J'ai appris tout ce que je sais sur la programmation orientée objet de Perl, précisément parce que c'est tout l'auto-assemblage, et c'est mon premier choix pour une langue d'enseignement.


Intéressant. Je suppose que cela dépend de qui sont vos élèves. Mes étudiants (humanités) ont besoin de savoir comment conduire la voiture, pas comment le sortir et le remettre ensemble.


Je pense qu'un "join itératif" seul serait trop étroit. Si la signification de "dans un contexte de liste" est de construire toute la liste avant de le transmettre comme un argument, alors c'est comme ça. J'éluais effectivement des concepts de python (qui sont "transparents" de manière très différente).


Il existe clairement de nombreux niveaux à cela, et ma secrétaire, qui est très clairement un «programmeur», car elle traite quotidiennement la complexité du MS Word, n'a pas besoin de savoir sur la programmation orientée objet. Cependant, je suis certain que ma conduite est améliorée en sachant ce qui se passe dans le moteur lorsque je appuie sur les pédales et que ma programmation est améliorée par l'expérience Assembleur et en sachant ce que j'implique quand j'appelle Strcpy . Bien sûr, nous ne pouvons pas tous garder des onglets sur toutes les conséquences de tout ce que nous faisons, mais la fondation est essentielle.


Le comportement de toute fonction PERL dans le contexte de la liste est entièrement basse à cette fonction. Une fonction ne peut effectuer qu'un seul appel de retour et il n'y a pas de support Itérateur intégré. Cependant, il n'y a aucune raison pour que je ne devrais pas écrire une classe avec un __ iTer __ méthode et un suivant méthode qui se comporte de manière cachée de Python.


Pas de question là-bas: l'expert bénéficie d'une connaissance de chaque partie de la fondation du système. J'aime bien savoir ce qui est sous le capot aussi. Mais les étudiants ... c'est une question différente. Je n'entraînerais pas les concepts de haut niveau des boulonnements, il vaincra tout le point d'abstraction.



-3
votes
use File::Slurp qw/read_file/;
my $text = read_file( 'filename' ) ;

1 commentaires

Comment cela aide-t-il à lire plusieurs fichiers spécifiés comme arguments de commande? Fichier :: SLURP est bon de savoir, mais cela ne répond pas à la question.