web-dev-qa-db-fra.com

Comment extraire du texte dans une chaîne de texte

J'ai un problème simple que j'espère résoudre sans utiliser VBA, mais si c'est la seule façon de le résoudre, qu'il en soit ainsi.

J'ai un fichier avec plusieurs lignes (toutes une colonne). Chaque ligne contient des données qui ressemblent à ceci:

1 7.82E-13> gi | 297848936 | réf | XP_00 | 4-hydroxyde gi | 297338191 | fr | 23343 | aléatoire

2 5.09E-09> gi | 168010496 | réf | xp_00 | 2-pyruvate

etc...

Ce que je veux, c'est un moyen d'extraire la chaîne de nombres commençant par "gi |" et terminez par un "|". Pour certaines lignes, cela peut signifier jusqu'à 5 chiffres gi, pour d'autres, ce n'en sera qu'un.

J'espère que la sortie ressemblera à quelque chose comme:

297848936,297338191

168010496

etc...

16
Brandon

Voici une réponse VBA très flexible utilisant l'objet regex. La fonction extrait toutes les correspondances de sous-groupes qu'elle trouve (éléments à l'intérieur de la parenthèse), séparés par la chaîne de votre choix (la valeur par défaut est ","). Vous pouvez trouver des informations sur les expressions régulières ici: http://www.regular-expressions.info/

Vous l'appeleriez comme ceci, en supposant que la première chaîne est en A1:

=RegexExtract(A1,"gi[|](\d+)[|]")

Puisque cela recherche toute occurrence de "gi |" suivi d'une série de chiffres puis d'un autre "|", pour la première ligne de votre question, cela vous donnerait ce résultat:

297848936, 297338191

Exécutez simplement cela dans la colonne et vous avez terminé!

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

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

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 & (separator & allMatches.Item(i).submatches.Item(j))
    Next
Next

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

RegexExtract = result

End Function
46
aevanko

La voici (en supposant que les données se trouvent dans la colonne A)

=VALUE(LEFT(RIGHT(A1,LEN(A1) - FIND("gi|",A1) - 2),
FIND("|",RIGHT(A1,LEN(A1) - FIND("gi|",A1) - 2)) -1 ))

Ce n'est pas la meilleure formule, mais cela fonctionnera pour extraire le nombre.

Je viens de remarquer que vous avez deux valeurs par ligne avec une sortie séparée par des virgules. Vous devrez vérifier s'il existe une deuxième correspondance, une troisième correspondance, etc. pour le faire fonctionner pour plusieurs numéros par cellule.

En référence à votre échantillon exact (en supposant 2 valeurs maximum par cellule), le code suivant fonctionnera:

=IF(ISNUMBER(FIND("gi|",$A1,FIND("gi|", $A1)+1)),CONCATENATE(LEFT(RIGHT($A1,LEN($A1)
- FIND("gi|",$A1) - 2),FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2)) -1 ), 
", ",LEFT(RIGHT($A1,LEN($A1) - FIND("gi|",$A1,FIND("gi|", $A1)+1) 
- 2),FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1,FIND("gi|", $A1)+1) - 2)) 
-1 )),LEFT(RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2),
FIND("|",RIGHT($A1,LEN($A1) - FIND("gi|",$A1) - 2)) -1 ))

Comment est-ce pour laid? Une solution VBA peut être meilleure pour vous, mais je vais laisser cela ici pour vous.

Pour aller jusqu'à 5 nombres, eh bien, étudiez le modèle et recursez manuellement dans la formule. Ça va devenir long!

6
Zelgada

Je diviserais probablement les données d'abord sur le | délimiteur à l'aide de l'assistant de conversion de texte en colonnes. Dans Excel 2007 qui se trouve dans l'onglet Données, Outils de données puis choisissez Texte vers colonnes. Spécifiez Autre: et | comme délimiteur.

À partir des exemples de données que vous avez publiés, il semble qu'après cela, les chiffres seront tous dans les mêmes colonnes afin que vous puissiez ensuite simplement supprimer les colonnes que vous ne voulez pas.

2
Jason S

Comme les autres gars ont présenté la solution sans VBA ... je présenterai celle qui l'utilise. Maintenant, c'est votre appel à l'utiliser ou non.

Je viens de voir que @Issun a présenté la solution avec regex, très sympa! Quoi qu'il en soit, présentera une solution "modeste" à la question, en utilisant uniquement du VBA "simple".

Option Explicit
Option Base 0

Sub findGi()

    Dim oCell As Excel.Range
    Set oCell = Sheets(1).Range("A1")

    'Loops through every row until empty cell
    While Not oCell.Value = ""

        oCell.Offset(0, 1).Value2 = GetGi(oCell.Value)
        Set oCell = oCell.Offset(1, 0)

    Wend

End Sub

Private Function GetGi(ByVal sValue As String) As String

    Dim sResult As String
    Dim vArray As Variant
    Dim vItem As Variant
    Dim iCount As Integer

    vArray = Split(sValue, "|")
    iCount = 0

    'Loops through the array...
    For Each vItem In vArray

        'Searches for the 'Gi' factor...
        If vItem Like "*gi" And UBound(vArray) > iCount + 1 Then

            'Concatenates the results...
            sResult = sResult & vArray(iCount + 1) & ","

        End If

        iCount = iCount + 1

    Next vItem

    'And removes trail comma
    If Len(sResult) > 0 Then

        sResult = Left(sResult, Len(sResult) - 1)

    End If

    GetGi = sResult

End Function
2
Tiago Cardoso