web-dev-qa-db-fra.com

Renvoyer une correspondance regex dans VBA (Excel)

J'essaie d'écrire une fonction pour Excel 2010 qui prend une cellule de texte non structuré, recherche une valeur appelée sdi et, si elle est trouvée, renvoie ce nombre. La valeur sdi apparaîtra sous la forme sdi ####. Ce que je veux, c'est renvoyer sdi et les numéros qui le suivent, ainsi si la cellule contient "du texte sdi 1234 un peu plus de texte", la fonction renverra sdi 1234.

Ceci est ma fonction:

Function SdiTest(LookIn As String) As String
  Dim temp As String
  Dim STA As Object
  temp = ""

  Set SDI = CreateObject("VBScript.RegExp")
  SDI.IgnoreCase = True
  SDI.Pattern = "sdi [1-9]*"
  SDI.Global = True

  If SDI.Test(LookIn) Then
    temp = SDI.Execute(LookIn)
  End If

  SdiTest = temp
End Function

S'il n'y a pas de numéro sdi, il n'entre jamais dans l'instruction if et renvoie consciencieusement la chaîne vide. S'il y a un numéro sdi, j'obtiens #VALUE!

Qu'est-ce que je rate?

Oui, VBScript est activé. De plus, je trouve frustrant d’utiliser Regex dans VBA et il est difficile de trouver des informations utiles en ligne. Des liens vers de bonnes ressources en ligne seraient appréciés.

Merci

44
TheoRose

Vous devez accéder aux matchs pour obtenir le numéro SDI. Voici une fonction qui le fera (en supposant qu'il n'y a qu'un seul numéro SDI par cellule).

Pour la regex, j'ai utilisé "sdi suivi d'un espace et d'un ou plusieurs nombres". Vous avez "sdi suivi d'un espace et de zéro ou plusieurs nombres". Vous pouvez simplement changer le + en * dans mon modèle pour revenir à ce que vous aviez.

Function ExtractSDI(ByVal text As String) As String

Dim result As String
Dim allMatches As Object
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")

RE.pattern = "(sdi \d+)"
RE.Global = True
RE.IgnoreCase = True
Set allMatches = RE.Execute(text)

If allMatches.count <> 0 Then
    result = allMatches.Item(0).submatches.Item(0)
End If

ExtractSDI = result

End Function

Si une cellule peut avoir plusieurs numéros SDI à extraire, voici ma fonction RegexExtract. Vous pouvez passer un troisième paramètre pour séparer chaque match (comme pour les séparer par des virgules) et entrer manuellement le motif dans l'appel de fonction réel:

Ex) =RegexExtract(A1, "(sdi \d+)", ", ")

Voici:

Function RegexExtract(ByVal text As String, _
                      ByVal extract_what As String, _
                      Optional seperator As String = "") As String

Dim i As Long, j As Long
Dim result As String
Dim allMatches As Object
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")

RE.pattern = extract_what
RE.Global = True
Set allMatches = RE.Execute(text)

For i = 0 To allMatches.count - 1
    For j = 0 To allMatches.Item(i).submatches.count - 1
        result = result & seperator & allMatches.Item(i).submatches.Item(j)
    Next
Next

If Len(result) <> 0 Then
    result = Right(result, Len(result) - Len(seperator))
End If

RegexExtract = result

End Function

* Veuillez noter que j'ai pris "RE.IgnoreCase = True" dans mon RegexExtract, mais vous pouvez le rajouter, ou même l'ajouter en tant que 4ème paramètre facultatif si vous le souhaitez.

71
aevanko