IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Pierre Fauconnier

VBA: Remplacer plusieurs parties de texte d'un seul coup

Note : 3 votes pour une moyenne de 3,67.
par , 21/10/2019 à 08h07 (1359 Affichages)
Salut.

Il arrive régulièrement que l'on doive recomposer des chaines de caractères en concaténant plusieurs sous-chaines. C'est le cas, par exemple, lorsque l'on recompose une chaine SQL en Access pour modifier une requête de sélection, ou en Excel lorsque l'on crée le texte d'une formule qui sera utilisée par AVALUATE.

Je vais illustrer la technique en recomposant un lien hypertexte contenant des parties fixes, qui ne changent donc jamais, et des parties mobiles. Cet exemple simple permettra de comprendre la technique mise en place. Dans plusieurs de mes prochains billets, je l'utiliserai dans des cas plus complexes.

Je dois recomposer le lien suivant:
<A href="https://www.google.fr/maps/dir/Place du Perron,+4910+Theux/Place Verte,+4900+Spa">Cliquez ici pour la navigation.</A>dans lequel on comprend bien que les deux adresses sont variables.

Je peux bien sûr utiliser le code suivant:
Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
Sub Test1()
  Dim Message As String
  Dim AdresseDepart As String, AdresseArrivee As String
 
  AdresseDepart = "Place du Perron,+4910+Theux"
  AdresseArrivee = "Place Verte,+4900+Spa"""
 
  Message = "<A href=""https://www.google.fr/maps/dir/" & AdresseDepart & "/" & AdresseArrivee & """>Cliquez ici pour la navigation.</A>"
End Sub

On remarque que le doublement des guillemets et l'insertion du / entre les adresses complexifient la saisie du code. L'exemple cité ici est simple, mais vous pourrez imaginer la complexification avec un nombre plus élevé de variables à insérer, surtout si elles sont de différents types (dates, valeurs décimales, ...) (un peu comme dans cette discussion qui aligne un nombre invraisemblable de "mauvaises pratiques". Allez vous y retrouver dans tous ces guillemets... ).

Pour éviter cette recomposition à la volée, j'utilise un système de balises à remplacer par les bonnes valeurs, comme dans l'exemple suivant où les adresses sont balisées dans la chaîne générique, ces balises étant remplacées par les variables correctes après coup. Par convention, les balises que j'utilise sont bornées par les accolades {}.
Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
Sub Test2()
  Dim Message As String
  Dim AdresseDepart As String, AdresseArrivee As String
 
  AdresseDepart = "Place du Perron,+4910+Theux"
  AdresseArrivee = "Place Verte,+4900+Spa"""
 
  Message = "<A href=""https://www.google.fr/maps/dir/{depart}/{arrivee}"">Cliquez ici pour la navigation.</A>"
  Message = Replace(Message, "{depart}", AdresseDepart, , , vbTextCompare)
  Message = Replace(Message, "{arrivee}", AdresseArrivee, , , vbTextCompare)
End Sub

Bien entendu, il y aura autant de Replace qu'il y a de valeurs à remplacer. Je déconseille l'écriture suivante qui, si elle tient plus ou moins la route pour deux valeurs, devient vite ingérable. Je rappelle que l'idée est de simplifier le code, pas d'en complexifier la saisie.
Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
Sub Test3()
  Dim Message As String
  Dim AdresseDepart As String, AdresseArrivee As String
 
  AdresseDepart = "Place du Perron,+4910+Theux"
  AdresseArrivee = "Place Verte,+4900+Spa"""
 
  Message = "<A href=""https://www.google.fr/maps/dir/{depart}/{arrivee}"">Cliquez ici pour la navigation.</A>"
  Message = Replace(Replace(Message, "{depart}", AdresseDepart, , , vbTextCompare), "{arrivee}", AdresseArrivee, , , vbTextCompare)
End Sub

J'ai donc opté pour la création d'une fonction générique qui va traiter cela en une fois grâce à un tableau de paires Clé/Valeur qui sera utilisé au sein d'une boucle. Cette fonction, générique et utilisable en VBA (non liée à Excel, donc), sera bien sûr placée dans mon module Tools.
Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
Public Function ReplaceStrings(Source As String, Parameters) As String
  Dim I As Long
 
  ReplaceStrings = Source
  For I = LBound(Parameters) To UBound(Parameters) Step 2
    ReplaceStrings = Replace(ReplaceStrings, Parameters(I), Parameters(I + 1), 1, -1, vbTextCompare)
  Next I
End Function

Son utilisation est très simple. Il suffit de lui passer la chaine contenant les balises {...} et le tableau des paires Clé/Valeur à remplacer.
Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
Sub Test4()
  Dim Message As String
  Dim AdresseDepart As String, AdresseArrivee As String
 
  AdresseDepart = "Place du Perron,+4910+Theux"
  AdresseArrivee = "Place Verte,+4900+Spa"""
 
  Message = "<A href=""https://www.google.fr/maps/dir/{depart}/{arrivee}"">Cliquez ici pour la navigation.</A>"
  Message = ReplaceStrings(Message, Array("{depart}", AdresseDepart, "{arrivee}", AdresseArrivee))
End Sub

Parmi les avantages de cette technique, je citerai:
  • la lisibilité du code;
  • la possibilité de remplacer des textes grâce à une ligne de code dans le code "métier";
  • la possibilité d'utiliser un tableau de paires clé/valeur sur un texte générique, ce tableau pouvant être des cellules Excel, un fichier CSV, un extract XML;
  • l'utilisation de l'argument Compare = vbCompareText qui ne lie pas la fonction aux options de compilation éventuellement présentes au début du module.



Dans certains de mes prochains billets qui illustreront des snippets (procédures ou fonctions génériques à réutiliser dans le code), cette fonction ReplaceStrings aura une place de choix...

Bon travail avec VBA

Envoyer le billet « VBA: Remplacer plusieurs parties de texte d'un seul coup » dans le blog Viadeo Envoyer le billet « VBA: Remplacer plusieurs parties de texte d'un seul coup » dans le blog Twitter Envoyer le billet « VBA: Remplacer plusieurs parties de texte d'un seul coup » dans le blog Google Envoyer le billet « VBA: Remplacer plusieurs parties de texte d'un seul coup » dans le blog Facebook Envoyer le billet « VBA: Remplacer plusieurs parties de texte d'un seul coup » dans le blog Digg Envoyer le billet « VBA: Remplacer plusieurs parties de texte d'un seul coup » dans le blog Delicious Envoyer le billet « VBA: Remplacer plusieurs parties de texte d'un seul coup » dans le blog MySpace Envoyer le billet « VBA: Remplacer plusieurs parties de texte d'un seul coup » dans le blog Yahoo

Commentaires

  1. Avatar de Blahite
    • |
    • permalink
    Bonjour,

    Assez intéressant.
    Une raison particulière de ne pas utiliser les dictionnaires ?
    S'il y a beaucoup de paramètre cela simplifie le code et la lisibilité à première vue.
    Exemple ci-dessous (adaptation à l'arrache, il y a peut-être mieux à faire en terme de binding)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Public Function ReplaceStrings(Source As String, ByRef dict) As String
      Dim I As Long
      Dim key As Variant
     
      ReplaceStrings = Source
    
      For Each key In dict.Keys
        ReplaceStrings = Replace(ReplaceStrings, key, dict(key), 1, -1, vbTextCompare)
      Next key
    End Function
    
    Sub Test4()
      Dim Message As String
      Dim dict As Object
      Set dict = CreateObject("Scripting.Dictionary")
      
      dict("{depart}") = "Place du Perron,+4910+Theux"
      dict("{arrivee}") = "Place Verte,+4900+Spa"""
     
      Message = "<A href=""https://www.google.fr/maps/dir/{depart}/{arrivee}"">Cliquez ici pour la navigation.</A>"
      Message = ReplaceStrings(Message, dict)
    End Sub
  2. Avatar de Pierre Fauconnier
    • |
    • permalink
    Salut.

    Perso, je ne suis pas un grand fan des dictionnaires. Ici, j'ai repris une fonction que j'utilise depuis longtemps en passant un tableau à une dimension (elle provient d'un framework MVC en PHP que j'ai créé il y a quelques années). On pourrait éventuellement utiliser un tableau à deux dimensions qui matérialise peut-être mieux les paires Ancienne valeur/Nouvelle valeur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Public Function ReplaceStrings(Source As String, Parameters) As String
      Dim I As Long
     
      ReplaceStrings = Source
      For I = LBound(Parameters) To UBound(Parameters)
        ReplaceStrings = Replace(ReplaceStrings, Parameters(I, LBound(Parameters, 2)), Parameters(I, UBound(Parameters, 2)), vbTextCompare)
      Next I
    End Function
    
    Sub Test()
      Dim t(1, 1)
      Dim s As String
      
      t(0, 0) = "{Femme}"
      t(0, 1) = "Martine"
      t(1, 0) = "{Homme}"
      t(1, 1) = "Pierre"
    
      s = "{Femme} et {Homme}"
      s = ReplaceStrings(s, t)
    End Sub
    Toutefois, que ce soit avec un dico ou un tableau à deux dimensions, il faut passer par une variable pour alimenter le tableau. Un tableau à une dimension peut être peuplé comme je le montre dans le code initial avec Array(...), ce qui a l'avantage de la concision au niveau du code.

    EN VBA/Excel, on pourrait utiliser t = [{"{Femme}","Martine";"{Mari}","Pierre"}] pour créer le tableau à deux dimensions, mais je préfère que la fonction soit la plus générique possible. C'est pourquoi le tableau à une dimension offrant la possibilité d'utiliser la fonction Array a ma préférence.