Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

s/// en Python dans les scripts

10 réponses
Avatar
Tribulations Parallèles
Bonjour à tous,

Je me mets à Python; connaissant un peu Perl et les outils traditionnels
Unix (sed, awk, expressions régulières), je me demande comment écrire en
Python ce genre de bout de code extrait de l'un de mes programmes (voir
ci-dessous). Le code permet de faire un "edit in place" du fichier
$path/$name/$name.lyx sans passer par un fichier temporaire, et d'utiliser
l'opérateur de substitution s/// de manière simple sur le fichier.

Comment réaliser une chose équivalente en Python, le plus simplement
possible?

Julien

==== extrait de code
# cf http://www.unix.org.ua/orelly/perl/cookbook/ch07_10.htm
# local permet de changer la valeur locale (innermost block, eval, ou
# file) d'une variable déjà existante, ici des variables
# d'environnement. Ici on veut émuler le -i de Perl en ligne de
# commande.
local @ARGV = "$path/$name/$name.lyx";
local $^I = ''; # remplacer par ".orig" pour garder une
#copie du fichier temporaire.
while ( <> )
{
s/Auteur\(s\) - Titre/$author - $title/;
s/auteur_coucou/$author_name/;
s/Fey01/$label/;
print;
}
====



--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).

10 réponses

Avatar
Bruno Desthuilliers
Bonjour à tous,

Je me mets à Python; connaissant un peu Perl et les outils traditionnels
Unix (sed, awk, expressions régulières), je me demande comment écrire en
Python ce genre de bout de code extrait de l'un de mes programmes (voir
ci-dessous). Le code permet de faire un "edit in place" du fichier
$path/$name/$name.lyx sans passer par un fichier temporaire, et d'utiliser
l'opérateur de substitution s/// de manière simple sur le fichier.

Comment réaliser une chose équivalente en Python, le plus simplement
possible?


Je ne suis pas sûr que Python soit le meilleurs outil pour ce genre de
traitements. Pas ce que ce soit impossible, bien sûr, mais c'est AMHA
typiquement un job pour Perl.

Julien

==== extrait de code
# cf http://www.unix.org.ua/orelly/perl/cookbook/ch07_10.htm
# local permet de changer la valeur locale (innermost block, eval, ou
# file) d'une variable déjà existante, ici des variables
# d'environnement. Ici on veut émuler le -i de Perl en ligne de
# commande.
local @ARGV = "$path/$name/$name.lyx";
local $^I = ''; # remplacer par ".orig" pour garder une
#copie du fichier temporaire.
while ( <> )
{
s/Auteur(s) - Titre/$author - $title/;
s/auteur_coucou/$author_name/;
s/Fey01/$label/;
print;
}
=== >




Avatar
William Dode
On 15-03-2007, Tribulations Parallèles wrote:
Bonjour à tous,

Je me mets à Python; connaissant un peu Perl et les outils traditionnels
Unix (sed, awk, expressions régulières), je me demande comment écrire en
Python ce genre de bout de code extrait de l'un de mes programmes (voir
ci-dessous). Le code permet de faire un "edit in place" du fichier
$path/$name/$name.lyx sans passer par un fichier temporaire, et d'utiliser
l'opérateur de substitution s/// de manière simple sur le fichier.

Comment réaliser une chose équivalente en Python, le plus simplement
possible?


Avec la méthode replace de string

machaine.replace("Auteur(s) - Titre", "%s - %s" % (auteur, titre))


Pour récupérer les variables d'environnement on utilise os.environ qui
est un dictionnaire. Ca pourrait donc donner

machaine.replace("Auteur(s) - Titre", "%(auteur)s - %(titre)s" % os.environ)



Julien

==== extrait de code
# cf http://www.unix.org.ua/orelly/perl/cookbook/ch07_10.htm
# local permet de changer la valeur locale (innermost block, eval, ou
# file) d'une variable déjà existante, ici des variables
# d'environnement. Ici on veut émuler le -i de Perl en ligne de
# commande.
local @ARGV = "$path/$name/$name.lyx";
local $^I = ''; # remplacer par ".orig" pour garder une
#copie du fichier temporaire.
while ( <> )
{
s/Auteur(s) - Titre/$author - $title/;
s/auteur_coucou/$author_name/;
s/Fey01/$label/;
print;
}
=== >





--
William Dodé - http://flibuste.net
Développeur informatique indépendant

Avatar
Tribulations Parallèles
William Dode wrote:

Avec la méthode replace de string

machaine.replace("Auteur(s) - Titre", "%s - %s" % (auteur, titre))


Pour récupérer les variables d'environnement on utilise os.environ qui
est un dictionnaire. Ca pourrait donc donner

machaine.replace("Auteur(s) - Titre", "%(auteur)s - %(titre)s" %
os.environ)


Merci pour ta réponse; si je ne m'abuse, cela ne permet pas de faire
un "edit-in-place"?

Julien

--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).

Avatar
William Dode
On 15-03-2007, Tribulations Parallèles wrote:
William Dode wrote:

Avec la méthode replace de string

machaine.replace("Auteur(s) - Titre", "%s - %s" % (auteur, titre))


Pour récupérer les variables d'environnement on utilise os.environ qui
est un dictionnaire. Ca pourrait donc donner

machaine.replace("Auteur(s) - Titre", "%(auteur)s - %(titre)s" %
os.environ)


Merci pour ta réponse; si je ne m'abuse, cela ne permet pas de faire
un "edit-in-place"?


Non, il renvoi une nouvelle chaine (si c'est ce que tu veux dire par
edit-in-place ?)


--
William Dodé - http://flibuste.net
Développeur informatique indépendant


Avatar
Tribulations Parallèles
William Dode wrote:

Non, il renvoi une nouvelle chaine (si c'est ce que tu veux dire par
edit-in-place ?)


En fait, par edit in place, je parle du "sed -i" ou du "perl -i" qui permet
de modifier un fichier sans passer par un fichier temporaire. Le code perl
que j'ai proposé dans le post initial permet de faire un edit in place à
partir d'un script (alors que perl -i s'utilise en ligne de commande). Donc
ma question est de savoir si je peux faire un edit in place à partir d'un
script python, sans passer par un fichier temporaire.
Dans ta solution, j'ai l'impression qu'on travaille sur une string, et qu'on
ne peut pas travailler sur un fichier directement. A moins qu'un fichier
puisse être considéré comme une string dans certaines conditions?

Julien

--
"Allez, Monsieur, allez, et la foi vous viendra." (D'Alembert).

Avatar
Michel Claveau
Bonsoir !

je ne connais ni Perl, ni Sed.

Mais, si l'on remplace, dans un fichier, des chaînes par des chaînes
plus grande, on est obligé, soit de passer par un fichier temporaire,
soit de charger en mémoire le fichier entier, pour le récrire (à partir
de la première modif).





--
@-salutations

Michel Claveau
Avatar
Sébastien Kirche
Le 15 mars 2007 à 22:13, Michel Claveau a formulé :

Bonsoir !

je ne connais ni Perl, ni Sed.

Mais, si l'on remplace, dans un fichier, des chaînes par des chaînes
plus grande, on est obligé, soit de passer par un fichier temporaire,
soit de charger en mémoire le fichier entier, pour le récrire (à
partir de la première modif).


Il me semble bien que l'option -i de sed (pour in-place) passe par un
fichier temporaire pour remplacer le fichier d'origine à la fin (c'est
logique). Je ne vois pas pourquoi perl ne ferait pas pareil.
--
Sébastien Kirche

Avatar
Bruno Desthuilliers
William Dode wrote:


Non, il renvoi une nouvelle chaine (si c'est ce que tu veux dire par
edit-in-place ?)



En fait, par edit in place, je parle du "sed -i" ou du "perl -i" qui permet
de modifier un fichier sans passer par un fichier temporaire.


AMHA, ça passe par un fichier temporaire - difficile de faire autrement
si on ne travaille pas sur des champs binaires de taille fixe. Par
contre, ce fichier temporaire est géré par l'appli (interpréteur, ce que
tu veux), et c'est donc transparent pour l'utilisateur.

Et non, Python ne permet pas ça. Contrairement à Sed, Awk et Perl,
Python n'a pas été spécifiquement conçu pour ce genre d'opérations.


Avatar
Maric Michaud
Pas vraiment pour répondre à la question, Bruno a déjà noté que python
n'était pas prévu pour s'intégrer directement aux shell.

Bruno Desthuilliers wrote:

AMHA, ça passe par un fichier temporaire - difficile de faire autrement
si on ne travaille pas sur des champs binaires de taille fixe.


sed passe par un fichier temporaire, c'est le principe, il travaille ligne à
ligne, et ne doit pas échouer si la mémoire ne peut contenir le fichier à
lire comme le résultat.

:~/temp$ echo toto > tata
:~/temp$ sed -i "s/o/i/g" tata
:~/temp$ cat tata
titi
:~/temp$ strace sed -i "s/o/i/g" tata | more
...
open("tata", O_RDONLY) = 3
...
open("./sedMH3MgX", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
...
rename("./sedMH3MgX", "tata") = 0
...

Perl fonctionne bien sur le même principe, il ouvre le fichier est ensuite
le supprime (par l'appel système unlink), utilisant de ce fait une
propriété de filesystems unix qui garantissent que tant qu'un descripteur
de fichier est ouvert le fichier n'est pas écrasé (pas du tout sûr que ça
fonctionne sous Windows).

:~/temp$ (strace perl -pi -e "s/o/a/g" tata 2>&1 )| grep tata
...
open("tata", O_RDONLY) = 3
unlink("tata") = 0
open("tata", O_WRONLY|O_CREAT|O_EXCL, 0666) = 4

donc l'équivalent python c'est rigoureusement :

:~/temp$ cat pysed
#!/usr/bin/env python
import os
from sys import argv

input = open(argv[3])
os.unlink(argv[3])
output = open(argv[3], 'w')

for i in input :
output.write(i.replace(argv[1], argv[2]))

:~/temp$ cat tata
tootoo
tootoo

:~/temp$ ./pysed oo i tata
:~/temp$ cat tata
titi
titi


_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097

Avatar
Elby
Pour faire ce genre de manip typiquement perlienne, j'utilise le module
fileinput. J'ai retrouvé un script que j'avais fait pour nettoyer des
fichiers textes mal encodés, qui est un exemple assez simple
d'utilisation :

***************** clean_srt *************************
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-

"""
Petit script pour nettoyer des fichiers textes mal encodés

usage :
clean_srt *.srt
"""

from re import compile
import fileinput

# Dictionnaire contenant les symboles à remplacer
bad_char = {
'x92' : "'",
'x9c' : "oe",
}

# RE permettant de rechercher les symboles précédents
RE_bad_char = compile(r'[%s]' % ''.join(bad_char.keys()))

def get_good_char(m,good_charºd_char.get):
return good_char(m.group()[0])

# Utilisation du module fileinput pour faire des substitution
# à la volée en créant des fichiers de sauvegarde (.bak)
for line in fileinput.input(inplace=True, backup='.bak') :
print RE_bad_char.sub(get_good_char, line),


# vim: set et sts=4 ts=4:
********************************************************


L'intérêt du module fileinput est qu'il peut aussi être utilisé
avec des pipe, comme l'opérateur <> en perl :

cat old.srt | clean_srt > new.srt

--
Enjoy