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

Remplacer les occurrences de __TRUC__ dans une chaîne par les éléments d'une séquence

21 réponses
Avatar
Francois
Bonjour à tous,


J'ai une chaîne de caractères ch qui contient par exemple 20
occurrences de la chaîne "__TRUC__". Elle en contient 20 occurrences
exactement car ch a été construite comme ça. Et j'ai une séquence seq
contenant 20 chaînes, comme par exemple :

seq = ['a0','a1',...,'a19']


Comment faire de manière la plus simple possible pour remplacer :
- la première occurrence de "__TRUC__" dans ch par 'a0'
- la deuxième occurrence de "__TRUC__" dans ch par 'a1'
.
.
.
- la vingtième occurrence de "__TRUC__" dans ch par 'a19' ?


Je sais par exemple que ch.replace("__TRUC__","xxx") remplace
toutes les occurrences de "__TRUC__" dans ch par "xxx". J'aimerais bien
savoir si on peut faire sans trop se fatiguer la même chose sauf qu'on
ne remplace pas toutes les occurrences par une même chaîne, mais par les
éléments d'une séquence de chaînes.

Merci d'avance.


--
François

10 réponses

1 2 3
Avatar
Pierre Quentel
On 24 oct, 16:45, Francois wrote:
Bonjour à tous,

     J'ai une chaîne de caractères ch qui contient par exemple 20
occurrences de la chaîne "__TRUC__". Elle en contient 20 occurrences
exactement car ch a été construite comme ça. Et j'ai une séquence seq
contenant 20 chaînes, comme par exemple :

seq = ['a0','a1',...,'a19']

Comment faire de manière la plus simple possible pour remplacer :
- la première occurrence de "__TRUC__" dans ch par 'a0'
- la deuxième occurrence de "__TRUC__" dans ch par 'a1'
   .
   .
   .
- la vingtième occurrence de "__TRUC__" dans ch par 'a19' ?

     Je sais par exemple que ch.replace("__TRUC__","xxx") remplace
toutes les occurrences de "__TRUC__" dans ch par "xxx". J'aimerais bien
savoir si on peut faire sans trop se fatiguer la même chose sauf qu'on
ne remplace pas toutes les occurrences par une même chaîne, mais par les
éléments d'une séquence de chaînes.

Merci d'avance.

--
François



Bonjour,

Une solution possible avec les expressions régulières, effectivement
bien adaptées pour ce genre de situation :

==========
chaine = 20*("zzz _TRUC_ ")
subs = ["a%s" %i for i in range(20)]

import re

def repl(mo):
return subs.pop(0)

res = re.sub("_TRUC_",repl,chaine)
print res
=========

La fonction sub du module re prend trois arguments : le modèle
(pattern) à remplacer, la chaîne ou la fonction de remplacement, et la
chaîne de départ

Ici on utilise une fonction, repl(), qui renvoie simplement les
éléments de la liste de substitution les uns après les autres avec la
méthode pop() de cette liste

A+
Pierre
Avatar
Francois
Pierre Quentel a écrit :

Une solution possible avec les expressions régulières, effectivement
bien adaptées pour ce genre de situation :

[couic]

res = re.sub("_TRUC_",repl,chaine)


La fonction sub du module re prend trois arguments : le modèle
(pattern) à remplacer, la chaîne ou la fonction de remplacement, et la
chaîne de départ

Ici on utilise une fonction, repl(), qui renvoie simplement les
éléments de la liste de substitution les uns après les autres avec la
méthode pop() de cette liste



Merci beaucoup pour cet exemple très intéressant. J'avais bien pensé à
re.sub mais dans mon livre (Au cœur de Python vol 2 de W.J Chun) j'avais
ceci concernant la définition de sub :

« sub(motif, rempl, chaîne, max=0) remplace toutes les occurrences du
motif indiqué par la chaîne de remplacement, en effectuant au plus max
substitutions »

Je ne pensais pas que rempl pouvait être une fonction ce qui est bien
sûr indiqué par la doc officielle. En revanche j'ai du mal à comprendre
le fait que la fonction repl de votre exemple prenne un argument.
Effectivement, d'après la doc elle doit prendre un argument du type
objet match. Mais j'ai du mal à comprendre à quoi ça correspond un objet
match. Est-ce possible d'avoir une explication.

Par exemple avec

a = re.search("zz.z","_zzaz__zzbz___zzcz___")

a est soit None soit un objet de type match. Ici a n'est pas None bien
sûr, c'est un objet de type match. Mais à quoi correspond cet objet de
type match ? Me permet-il d'accéder à la sous chaîne "zzcz" par exemple
? Comment traduire le mot "match" en français ? "Associer" ?

Merci d'avance.


--
François
Avatar
Méta-MCI \(MVP\)
Bonsoir !

Pas plus que François, je n'avais pas noté qu'il était possible
d'utiliser une fonction pour la valeur de remplacement.

Dommage qu'un Generator soit refusé. Toutefois, on peut faire :
g=iter(seq)
ch = re.sub("__TRUC__", lambda x:g.next(), ch)



François : tu n'as pas jugé mon exemple avec reduce. Qu'est-ce à dire
?


@-salutations
--
Michel Claveau
Avatar
Bruno Desthuilliers
Francois a écrit :
Amaury Forgeot d'Arc a écrit :

Le remplacement change la longueur du texte, et décale les caractères
qui suivent ; même si on modifie l'objet en place, cela fait des
opérations en mémoire.



C'est bizarre mais dans cette phrase j'ai l'impression que tu supposes
que la chaîne est modifiée,



Non - Amaury décrit ce qui se passerait _si_ la chaine était modifiée.
Essaie de coder la même chose en C, et ce sera évident...
Avatar
Francois
Méta-MCI (MVP) a écrit :

François : tu n'as pas jugé mon exemple avec reduce. Qu'est-ce à dire ?



Tu veux sans doute parler parler de

ch = reduce(lambda a,b: a.replace("__TRUC__",b,1), seq, ch)

Je ne me permettrais pas de "juger". :-)
Ça marche parfaitement bien sûr et je pense que là, on ne pas faire plus
concis (avec la solution de Pierre Quentel utilisant re). Merci beaucoup
car ça été l'occasion pour moi de faire connaissance avec reduce.

Il est très probable que je revienne à la charge dans un nouveau fil
ultérieurement car ma question initiale était en rapport avec un petit
script que je souhaite réaliser pour me rendre quelques services.


--
François
Avatar
Francois
Bruno Desthuilliers a écrit :

Le remplacement change la longueur du texte, et décale les caractères
qui suivent ; même si on modifie l'objet en place, cela fait des
opérations en mémoire.



C'est bizarre mais dans cette phrase j'ai l'impression que tu supposes
que la chaîne est modifiée,



Non - Amaury décrit ce qui se passerait _si_ la chaine était modifiée.



Mais alors quel est l'intérêt puisque de toutes façons les chaînes ne
sont pas modifiables ?


--
François
Avatar
Bruno Desthuilliers
Francois a écrit :
Bruno Desthuilliers a écrit :

Le remplacement change la longueur du texte, et décale les
caractères qui suivent ; même si on modifie l'objet en place, cela
fait des opérations en mémoire.



C'est bizarre mais dans cette phrase j'ai l'impression que tu
supposes que la chaîne est modifiée,



Non - Amaury décrit ce qui se passerait _si_ la chaine était modifiée.



Mais alors quel est l'intérêt puisque de toutes façons les chaînes ne
sont pas modifiables ?



C'était en réponse à tes "inquiétudes" concernant le coût potentiel en
ressources, je cite:

"""
à chaque itération, un nouvel objet chaîne est créé car les chaînes de
caractères ne sont pas modifiables en Python. On pourrait imaginer que
ça puisse être coûteux en ressource mémoire pour des grosses chaînes de
caractère
"""

Dans la mesure où la chaine de remplacement n'est pas de la même taille
que la chaine à remplacer (ie : remplacer '_TRUC_' par
"azertuiopqsdfghjklm"), il faudra de toutes façons allouer de la mémoire
supplémentaire. Effectivement, sur une "grosse" chaine de caractère
(vraiment grosse compte tenu de la RAM moyenne sur une machine
actuelle), ça peut devenir un bottleneck. Mais si tu sais que va traiter
des textes vraiment volumineux, tu choisis d'entrée de jeux une approche
différente qui évite de charger toute la chaine en mémoire - approche
qui serait probablement moins performante sur de petites chaines.
Avatar
Francois
Bruno Desthuilliers a écrit :

Dans la mesure où la chaine de remplacement n'est pas de la même taille
que la chaine à remplacer (ie : remplacer '_TRUC_' par
"azertuiopqsdfghjklm"), il faudra de toutes façons allouer de la mémoire
supplémentaire.



Ok, compris. Merci bien.

--
François
Avatar
Pierre Quentel
On 26 oct, 17:24, Francois wrote:
Pierre Quentel a écrit :

> Une solution possible avec les expressions régulières, effectivemen t
> bien adaptées pour ce genre de situation :

> [couic]

> res = re.sub("_TRUC_",repl,chaine)

> La fonction sub du module re prend trois arguments : le modèle
> (pattern) à remplacer, la chaîne ou la fonction de remplacement, et la
> chaîne de départ

> Ici on utilise une fonction, repl(), qui renvoie simplement les
> éléments de la liste de substitution les uns après les autres ave c la
> méthode pop() de cette liste

Merci beaucoup pour cet exemple très intéressant. J'avais bien pens é à
re.sub mais dans mon livre (Au cœur de Python vol 2 de W.J Chun) j'avai s
ceci concernant la définition de sub :

« sub(motif, rempl, chaîne, max=0) remplace toutes les occurrences du
motif indiqué par la chaîne de remplacement, en effectuant au plus ma x
substitutions »

Je ne pensais pas que rempl pouvait être une fonction ce qui est bien
sûr indiqué par la doc officielle. En revanche j'ai du mal à compre ndre
le fait que la fonction repl de votre exemple prenne un argument.
Effectivement, d'après la doc elle doit prendre un argument du type
objet match. Mais j'ai du mal à comprendre à quoi ça correspond un objet
match. Est-ce possible d'avoir une explication.

Par exemple avec

a = re.search("zz.z","_zzaz__zzbz___zzcz___")

a est soit None soit un objet de type match. Ici a n'est pas None bien
sûr, c'est un objet de type match. Mais à quoi correspond cet objet d e
type match ? Me permet-il d'accéder à la sous chaîne "zzcz" par exe mple
? Comment traduire le mot "match" en français ? "Associer" ?

Merci d'avance.

--
François



Bonsoir,

Une autre solution en une ligne:

print "".join(x+y for(x,y) in zip(chaine.split("_TRUC_"),subs))

Ca marche bien dans ce cas, mais ça vaut le coup de creuser un peu les
expressions régulières, c'est pas très intuitif au départ mais tr ès
puissant

Dans ton exemple :

a = re.search("zz.z","_zzaz__zzbz___zzcz___")

La fonction search() renvoie un "match object" (match =
correspondance) dont les attributs sont fournis dans la doc, par
exemple a.start() et a.end() donnent les positions de début et de fin
du pattern "zz.z" dans la chaîne

search() ne renvoie que la première correspondance, pour les avoir
toutes il faut utiliser la fonction findall() ou finditer():

for mo in re.finditer("zz.z","_zzaz__zzbz___zzcz___"):
print mo.string[mo.start():mo.end()]

A+
Pierre
Avatar
Pierre Maurette
Pierre Quentel, le 29/10/2008 a écrit :

[...]

Une autre solution en une ligne:

print "".join(x+y for(x,y) in zip(chaine.split("_TRUC_"),subs))

Ca marche bien dans ce cas,



Oui, dans ce cas. Avec:

chaine = 20*("zzz _TRUC_ ")

Mais le fait que la chaîne se termine par __TRUC__ est une exception. A
tester avec:

chaine = 20*("zzz _TRUC_ ") + "zzz"

ou tant qu'à faire:

chaine = "111 _TRUC_ 222 _TRUC_ 333 _TRUC_ 444 _TRUC_ 555 _TRUC_ 666"

(et la chaîne a le droit de commencer par __TRUC__, donc tester aussi:
chaine = "_TRUC_ 111 _TRUC_ 222 _TRUC_ 333 _TRUC_ 444 _TRUC_ 555"
)

Sur cette base, la coquetterie de le faire en une ligne se payerait par
un double appel à split(), puisque si j'ai bien lu une réponse qui m'a
été faite sur ce forum il ne faut pas espérer d'optimisation.
En deux lignes:

s = ch.split('zorglub')
result = ''.join([a[0] + a[1] for a in zip(s, seq)] + [s[-1]])

avait été proposé dans la première réponse ;-)

--
Pierre Maurette
1 2 3