[VBA] - Je ne comprends pas ce qu'Excel compte

Bonjour,

J'essaie de me servir des signes "—" pour rechercher des informations dans des cellules et les organiser en tableaux.

Ce nombre de "—" est quasiment constant dans chaque cellule et lorsque je demande de récupérer les infos après le 3ème "—", alors je sais ce dont il s'agira à chaque fois.

Dans mon code, je demande à Excel de compter ces "—" et de réagir en fonction du nombre relevé.

Sauf que là où j'en vois 3, Excel en voit 7...

Alors je demande à transformer les "—" en "_" au cas où ils compterait d'autres caractères.

Mais là où j'en vois toujours 3, cette fois il en voit 202...

Et ces erreurs de comptages engendrent des erreurs par la suite.

Vous savez d'où ça provient ? Qu'est ce qu'il faut mettre pour que ça fonctionne ?

Je ne peux pas utiliser de tiret du 6, par de chiffres, pas de lettres. Underscore était alors tout désigné.

Je joins un fichier avec le comptage auto des "—", et la ligne qui pose problème, surlignée en jaune.

J'espère que vous aurez une idée pour solutionner cette étrange erreur.

Bonne journée !

7testcomptage.xlsm (19.25 Ko)

Bonjour Le Drosophile le forum

si tu nous expliquais le pourquoi de ton comptage???

Le but c'est quoi???

Pour faire ce que tu veux tu est obligé de compter ??

dans l'attente d'explications

a+

Papou

EDIT : Bonjour Pedro22

Bonjour,

J'ai pas bien saisi ce que vous essayez de faire dans vos macros...

Je vous propose donc une autre solution avec une fonction personnalisée (code à coller dans un module standard de VBA) :

Public Function CompterCaractère(Cellule As Range, Car As String) As Integer

'Déclaration des variables
Dim Pos As Integer, Res As Integer

'Boucle sur chaque caractère de la cellule
For Pos = 1 To Len(Cellule)
    If Mid(Cellule, Pos, 1) = Car Then Res = Res + 1 'Si correspondance, on incrémente le compteur
Next Pos
CompterCaractère = Res 'Résultat de la fonction

End Function

A utiliser ensuite dans la feuille comme une fonction classique :

=CompterCaractère(A2;"—")

edit : salut paritec !

(suite)

Adaptation de la fonction précédente pour gérer aussi des plages de plusieurs cellules :

Public Function CompterCaractère(Plage As Range, Car As String) As Integer

Dim Pos As Integer, Res As Integer, Cellule As Range

For Each Cellule In Plage
    For Pos = 1 To Len(Cellule)
        If Mid(Cellule, Pos, 1) = Car Then Res = Res + 1
    Next Pos
Next Cellule
CompterCaractère = Res

End Function
=CompterCaractère(A2;"—")
=CompterCaractère(A2:A100;"—")

Bonjour,

Pour répondre rapidement à vos interrogations :

Je compte pour récupérer les infos dans différentes colonne, exemple :

"NPh — III-V — 1,5-4 m — littoral Côte d’Azur ; naturalisé — rocailles, vieux murs — Centre-afr. — A. arbore-i, -o"

4ème "—" = "rocailles, vieux murs" => Colonne [C]

5ème "—" = "Centre-afr." => Colonne [D]

etc.

Mais lorsqu'il n'y a pas 3, 4 ou 5 tirets, alors Excel génère une erreur.

Après j'ai également des exceptions comme ici :

"V-VII — 1-4 dm — pelouses xérophiles basiphiles"

Qu'il me faudra traiter à part probablement car il n'y a pas de 3ème ou 4ème tiret.

Je reviens vers vous quand j'aurai fait les tests !

Merci !

Toujours pas sûr d'avoir saisit l'idée...

Si tu souhaites séparer des infos sur la base du caractère "_", utilise la fonctionnalité "convertir" ("Données" --> "Convertir") avec un séparateur personnalisé. Tes données seront alors placées dans des colonnes différentes.

Sous VBA, la fonction Split() produit un résultat similaire. Tu peux conditionner son utilisation au nombre de "_" dans ta cellule pour séparer ou non des infos.

Oui j'utilise "split" dans ce code (qui risque de paraître un peu flou sans document rattaché) :

With tb
For Each cel2 In Range("A1:A" & lrA)
    If cel2 = "" Then
    Else
        If cel2.Characters(1, 1).Font.Italic = True Then
        Else
            If Left(cel2.Value, 1) = "1" Or Left(cel2.Value, 1) = "2" Or Left(cel2.Value, 1) = "3" _
            Or Left(cel2.Value, 1) = "4" Or Left(cel2.Value, 1) = "5" Or Left(cel2.Value, 1) = "6" _
            Or Left(cel2.Value, 1) = "7" Or Left(cel2.Value, 1) = "8" Or Left(cel2.Value, 1) = "9" _
            Or Left(cel2.Value, 1) = "a" Or Left(cel2.Value, 1) = "g" Or Left(cel2.Value, 1) = "b" _
            Or Left(cel2.Value, 1) = "c" Then
            Else
                If Not UCase(cel2.Value) Like "*—*" Then
                Else
                    'For e = 1 To Len(cel2)
                        'If .Characters(e, 1) = "—" Then
                            'total = total + 1
                                'If total > 3 Then
                                If InStr(1, cel2, "—") > 3 Then
                                    cel2.Offset(0, 5).Value = Split(Trim(cel2.Value), "—")(3)
                                    cel2.Offset(0, 3).Value = Split(Trim(cel2.Value), "—")(4)
                                End If
                                If InStr(1, cel2, "—") > 4 Then
                                    cel2.Offset(0, 4).Value = Split(Trim(cel2.Value), "—")(5)
                                Else
                                End If
                        'End If
                    'Next e
                End If
            End If
        End If
    End If
Next cel2
End With

Et ce code génère des erreurs lorsqu'il n'y a pas 3 4 ou 5 tirets.

Alors j'ai rajouté des lignes pour compter ces tirets et n'exécuter le code que sur les cellules qui respectent la règle. Mais c'est en voulant compter le nombre de tirets que je constate qu'il en compte plus qu'il n'y en a, et me génère donc quand même des erreurs.

Je ne peux pas tester la proposition de code pour le moment, mais je le fait dès que possible !

Sauf erreur de ma part, ce code n'est pas dans votre fichier joint...

Un essai :

Sub Test()

Dim tb As Worksheet, Cel2 As Range

Set tb = Worksheets("Feuil1")
With tb
    For Each Cel2 In .Range("A1:A" & lrA)
        If Not Cel2 = "" Then
            If Not Cel2.Characters(1, 1).Font.Italic = True Then
                Select Case Left(Cel2.Value, 1)
                    Case 1 To 9, "a", "b", "c", "g"
                        'Ne rien faire
                    Case Else
                        If UCase(Cel2.Value) Like "*—*" Then
                            If CompterCaractère(Cel2, "—") > 3 Then
                                If InStr(1, Cel2, "—") > 3 Then
                                    Cel2.Offset(0, 5) = Split(Trim(Cel2), "—")(3)
                                    Cel2.Offset(0, 3) = Split(Trim(Cel2), "—")(4)
                                End If
                                If InStr(1, Cel2, "—") > 4 Then Cel2.Offset(0, 4) = Split(Trim(Cel2), "—")(5)
                            End If
                        End If
                End Select
            End If
        End If
    Next Cel2
End With

End Sub
Public Function CompterCaractère(Plage As Range, Car As String) As Integer

Dim Pos As Integer, Res As Integer, Cellule As Range

For Each Cellule In Plage
    For Pos = 1 To Len(Cellule)
        If Mid(Cellule, Pos, 1) = Car Then Res = Res + 1
    Next Pos
Next Cellule
CompterCaractère = Res

End Function

Quelques remarques :

  • Dans une structure If condition Then machin Else Truc, la partie "Else" est facultative (donc autant s'arranger pour ne pas l'écrire et alléger le code si elle n'a pas d'intérêt)
  • Une variable incrémentée de la manière suivante dans une boucle : Total = Total + 1 doit être réinitialisée à chaque nouvelle boucle, sinon elle conserve ses valeurs précédentes, ce qui fausse le résultat
  • InStr ne compte pas le nombre d’occurrences d'un caractère dans une chaîne, mais donne la première position à laquelle il est rencontré
  • Pour avoir un intérêt, les objets au sein d'une structure With ObjetTruc ... End With doivent commencer par un "." s'ils se rattachent à ObjetTruc

Bonjour,

Il faut différencier le caractère "-" (moins : chr(45)) du caractère "—" chr(151)

Donc dans ton VBA au lieu d'utiliser les chaines "-" ou "—" utilise chr(45) ou chr(151)

A+

Bonsoir,

Merci beaucoup pour vos proposition ! J'ai beaucoup de tests à faire. Les premiers tests semblent donner de bon résultats

Je pense que cette procédure est extrêmement chronophage (il peut y avoir des milliers de caractères) ; je viens de lancer le script entier sur 6000 lignes et ça risque déjà de prendre un moment :

    For Pos = 1 To Len(Cellule)
        If Mid(Cellule, Pos, 1) = Car Then Res = Res + 1
    Next Pos
    

Comment ce fait-il qu'en écrivant : "Car " Excel soit en mesure de savoir qu'il s'agit de "—" ?

Je vais regarder tout ce que vous proposez, je pense qu'avez ça j'ai tout pour que ça fonctionne

Edit : Pour le moment j'ai une erreur sur la ligne :

If InStr(1, Cel2, "—") > 4 Then Cel2.Offset(0, 4) = Split(Trim(Cel2), "—")(5)

Arrivé ici : "a’ – Souche non tubéreuse (cultivé en grand dans toute la Fr., souvent échappé — colza — B. nap-i, -o) "

A plus tard !

L'utilisation de "Chr(151)" conduit à la même erreur, je ne sais pas ce qu'Excel compte quand j'utilise ce code :

InStr(1, Cel2, Chr(151))

Il compte beaucoup plus de tirets (ou moins) qu'il n'y en a de visibles.

Pour éviter le problème, je peux utiliser On error GOTO mais ça ne me dit pas comment corriger ça :/

Je joins un document, pour que vous puissiez voir, en attendant que je trouve (peut-être) l'origine du problème.

J'ai une autre petite question :

Quand on utilise ce code, est-il possible de conserver le format du texte qui est récupéré ?

Cel2.Offset(0, 5) = Split(Trim(Cel2), Chr(151))(3)
Cel2.Offset(0, 3) = Split(Trim(Cel2), Chr(151))(4)
4testcomptage.xlsm (25.12 Ko)

Je pense que cette procédure est extrêmement chronophage (il peut y avoir des milliers de caractères) ; je viens de lancer le script entier sur 6000 lignes et ça risque déjà de prendre un moment :

    For Pos = 1 To Len(Cellule)
        If Mid(Cellule, Pos, 1) = Car Then Res = Res + 1
    Next Pos

Bonjour,

Pour accélérer la procédure, ajoutez les instructions suivantes dans le code :

'En début de macro :
Application.Calculation = xlCalculationManual 'Désactive le recalcul auto des formules Excel
'...Le reste de la macro...
'En fin de macro :
Application.Calculation = xlCalculationAutomatic 'Réactive le recalcul auto 

Comment ce fait-il qu'en écrivant : "Car " Excel soit en mesure de savoir qu'il s'agit de "—" ?

Il faut lui préciser le caractère lors de l'appel de la fonction.

Edit : Pour le moment j'ai une erreur sur la ligne :

If InStr(1, Cel2, "—") > 4 Then Cel2.Offset(0, 4) = Split(Trim(Cel2), "—")(5)

Arrivé ici : "a’ – Souche non tubéreuse (cultivé en grand dans toute la Fr., souvent échappé — colza — B. nap-i, -o) "

J'ai laissé cette partie telle que vous l'aviez écrite, n'ayant pas en tête l'objectif de ces instructions.

Bonjour,

[Le Drosophile] Déjà ça serait bien que tu évite de nous donner des bouts de macro : Un bout de macro à autant de signification en soit qu'une peau de saucisson dans une assiette... Avec un peu d'imagination on peut deviner ce que c'est, mais c'est tout !

C'est pourquoi Pedro est aussi perplexe que moi devant ton Cel2...

Bon je n'ai traité que la Feuil1, mais pitêtre que ça va te donner des idées...

Sinon tu reviens avec des explications plus précises sur le résultat final que tu veux obtenir (sans me dicter par quel moyen tu comptes y parvenir) et avec un fichier un peu plus consistant et j'essaierai de dépiauter TOUSSA.

Mais tu évites surtout de me donner des tranches de saucisson car j'ai horreur de recommencer 10 fois le même travail par défaut d'explications !

A+

Bonjour,

Effectivement je peux manquer de clarté dans mes explications. Si je demande des petits bouts de codes, c'est pour essayer d'en faire le maximum moi-même. Cependant je ne sais pas toujours, comment correctement gérer mes données, et surtout, ce qui peut être fait avec VBA, par rapport à ce que je sais faire.

Je me lance alors d'après ce que je connais de VBA (pas grand chose) et me retrouve dans des situations plutôt complexes où j'en arrive à vous demander de l'aide en vous transmettant une source de données qui vous semble absurde.

En utilisant ce code là :

                            If CompterCaractère(Cel2, Chr(151)) > 3 Then
                                If InStr(1, Cel2, Chr(151)) > 3 Then
                                    Cel2.Offset(0, 1) = InStr(1, Cel2, Chr(151))
                                    Cel2.Offset(0, 2) = Split(Trim(Cel2), Chr(151))(3)
                                    Cel2.Offset(0, 3) = Split(Trim(Cel2), Chr(151))(4)
                                End If
                                If InStr(1, Cel2, Chr(151)) > 4 Then
                                    Cel2.Offset(0, 4) = Split(Trim(Cel2), Chr(151))(5)

J'essaie de diviser les informations contenues dans chaque cellule en fonction des "—"

Je vois que vous vous y prenez autrement : Split(Tablo(k, 1), Chr(151))

Et ça m'a déjà l'air clairement mieux.

Ci-joint, j'ai ajouté un document de travail dans lequel se trouve un peu plus des 500 premières lignes que j’essaie de traiter.

La feuille 2 "Résultat espéré" montre ce que j'essaie d'obtenir exactement. Ce qui n'est probablement pas possible étant donné les exceptions qui apparaissent et qui ne peuvent probablement pas être traitées (car rien ne permet de définir qu'il s'agit d'exceptions et comment récupérer l'information à l'intérieur).

Spoiler

Sans vouloir dicter le moyen par lequel je cherche à obtenir les informations que je place ensuite dans des colonne, tout ce que je peux dire c'est qu'elles sont identifiables grâce au nombre de "—" ; lorsqu'il y a des "—" dans une cellule alors, après le 3ème il s'agit des informations sur le ["la répartition en France"], après le 4ème "—" il s'agit d'informations sur le ["milieu"] et après le 5ème, il s'agit d'informations sur la ["Biogéographie"].

Entre ce que j'ai pu faire et l'aide que l'on m'a apporté, j'ai un code fonctionnel mais qui génère quelques erreurs. Il y a aussi des exceptions que je ne sais pas à gérer pour le moment. Mais peut-être qu'il faudrait revoir ma manière d'appréhender le problème...

En tout cas, vous avez à disposition le même support de travail et les mêmes codes que j'utilise, avec une feuille qui renseigne exactement ce que j'essaie d'obtenir.

J'ai l'impression de toucher au but, mais les exceptions (nombre de "—" qui varie notamment) qui trainent m'empêchent de terminer proprement.

Je n'ai pas encore bien pris le temps de regarder et de tester ce que vous proposez, je reviens plus tard !

Bonne journée !

1doc-travail-02.xlsm (218.34 Ko)

Je ne me suis occupé que des colonnes

Milieu Biogéographie Répartition France

...Encore que l'Espèce est récupérée aussi (colonne J) puis effacé car j'ai l'impression que tu as déjà les premières colonnes.

A+

1doc-travail-vg.xlsm (264.28 Ko)

Bonsoir,

Lorsque je réalise les tests sur un autre document de travail, j'ai l'erreur suivante :

"L'indice n'appartient pas à la sélection".

Dans le document que je joins, l'erreur apparaît à cette ligne :

Range("A1:M" & iLR) = Tablo

D'où cela peut venir d'après vous ?

J'avoue que je ne vois pas de raison à cette erreur... Je dois avoir un petit coup de pompe ?

J'ai essayé une autre syntaxe avec Ubound(Tablo), j'ai essayé de spécifier le nom de la feuille, mais je tourne un peu en rond.

J'ai essayé en inhibant toutes les autres macros de ce classeur mais ça ne marche pas non plus.

J'ai essayé en important tes nouvelles données dans le premier classeur et ça ne marche pas non plus...

On peut donc supposer que quelque chose dans ces nouvelles données bloque le transfert mais quoi ? Je donne ma langue à plus malin que moi !

A+

En fait je me demande si ça ne viendrait pas du code "recupdata" quand on lance la variable "bb" et qui génère une erreur en fonction du remplissage de la dernière ligne.

Message ultra clair... , j'expliquerai mieux si j'arrive à le faire fonctionner.

J'avoue que je ne vois pas de raison à cette erreur... Je dois avoir un petit coup de pompe ?

J'ai essayé une autre syntaxe avec Ubound(Tablo), j'ai essayé de spécifier le nom de la feuille, mais je tourne un peu en rond.

J'ai essayé en inhibant toutes les autres macros de ce classeur mais ça ne marche pas non plus.

J'ai essayé en important tes nouvelles données dans le premier classeur et ça ne marche pas non plus...

On peut donc supposer que quelque chose dans ces nouvelles données bloque le transfert mais quoi ? Je donne ma langue à plus malin que moi !

A+

Voici une autre macro qui fait le même boulot, malheureusement ça n'explique pas ce qui coince dans la précédente...

Et malheureusement également elle est beaucoup moins rapide...

Sub test()
Application.ScreenUpdating = False
Dim Tablo
Dim ARes, i&, k&, iLR&
With ActiveSheet
'Dernière Ligne :
iLR = .Cells(.Rows.Count, 1).End(xlUp).Row
Tablo = .Range("A1:M" & iLR).Value
For k = 2 To iLR
ARes = Split(Tablo(k, 1), Chr(151))
   For i = 1 To UBound(ARes)
      Tablo(k, 4) = i
      Tablo(k, i + 4) = ARes(i)
   Next i
Next k
For i = 1 To UBound(Tablo)
   .Cells(i, 7) = Tablo(i, 8)
   .Cells(i, 8) = Tablo(i, 9)
   .Cells(i, 9) = Tablo(i, 7)
Next
End With
End Sub

A+

Rechercher des sujets similaires à "vba comprends pas compte"