3
votes

Boucle simple à faire jusqu'à dans VBA

Je suis nouveau sur Excel VBA et j'ai une question simple. Une fois que je comprends comment faire cette boucle, je peux construire dessus.

Je voudrais automatiser une classification. Les données se répètent dans une seule colonne, c'est-à-dire sampleA, sampleA, sampleA, sampleB, sampleB, sampleC, sampleC, sampleC, etc. Je voudrais que ma macro identifie quand le nom de l'échantillon change entre les noms d'échantillon. Ainsi, par exemple, lorsque la cellule suivante après sampleA se transforme en sampleB, je voudrais que la macro comprenne qu'il y a un changement et écrive une phrase à côté de ceci (cela se transformera ensuite en une équation avec les données dans les lignes respectives de l'échantillon mais baby steps :)).

Dans l'ensemble, la macro a besoin de détecter les changements entre une colonne de noms d'échantillons identiques jusqu'à ce qu'un nouveau nom soit atteint.

J'ai recherché des solutions et la boucle «faire jusqu'à» semble être la solution la plus proche de ce dont j'ai besoin. Aussi, pour montrer que sampleA n'est pas le même que sampleB, j'ai utilisé .

Sample:  Classification
sampleA  --
sampleA  --
sampleA  hello
sampleB  --
sampleB  goodbye
sampleC  --
sampleC  --
sampleC  see you soon

Résultats réels: erreur au niveau des cellules (classification, "B ") .Valeur = réponse Quelque chose cloche ici. J'essaie d'afficher les résultats dans la colonne "B".

Résultats attendus sur la feuille de calcul Excel dans les colonnes:

Sub DoUntilStringMacro()

Dim sampleA As String

Dim sampleB As String

Dim sampleC As String

Dim classification As String

    Do Until ActiveCell.Value = ""

        If sampleA <> sampleB Then
            classification = "hello"
        ElseIf sampleB <> sampleC Then
            classification = "goodbye"
        ElseIf sampleC <> sampleA Then
            classification = "see you soon"
        End If

        answer = classification
        Cells(classification, "B").Value = answer

    Loop

End Sub


4 commentaires

Se fier à ActiveCell peut entraîner des problèmes. Au lieu d'utiliser une boucle Do Until , pensez peut-être à recherche de la dernière ligne , puis boucle de la ligne de départ à la dernière ligne.


SampleA etc. ne sont jamais initialisés et la cellule que vous attendez de quelque chose comme Cells ("goodbye", "B") depuis "n'est pas claire. au revoir " n'est manifestement pas un numéro de ligne.


Peut-il y avoir des cellules vides dans la plage? Et la classification peut-elle se répéter ou ne doit-elle intervenir que juste avant un changement? La dernière valeur avant le blanc de fin constitue-t-elle un changement (semble-t-il ...)? La commande des données est-elle garantie?


Vous avez omis des parties du code car on ne sait pas d'où viennent ces exemples variables. Si vous traitez avec ActiveCell , vous devez le faire avancer dans une boucle - sinon vous êtes coincé avec une seule et même cellule.


3 Réponses :


0
votes

Vous pouvez essayer la boucle For:

Option Explicit

Sub Change()

    Dim Lastrow As Long, Row As Long
    Dim PreviousString As String, CurrenctString As String

    'With statement refers to shee 1
    With ThisWorkbook.Worksheets("Sheet1")
        'Find last row in Sheet 1 - Column A
         Lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
        'Loop each row start from 3 to lastrow
        For Row = 3 To Lastrow
            PreviousString = .Range("A" & Row - 1).Value
            CurrenctString = .Range("A" & Row).Value

            'Check if both strings are not the same
            If PreviousString <> CurrenctString Then
                If PreviousString = "sampleA" And CurrenctString = "sampleB" Then
                    .Range("B" & Row - 1).Value = "hello"
                ElseIf PreviousString = "sampleB" And CurrenctString = "sampleC" Then
                    .Range("B" & Row - 1).Value = "goodbye"
                ElseIf PreviousString = "sampleC" And CurrenctString = "sampleD" Then
                    .Range("B" & Row - 1).Value = "see you soon"
                End If

            End If

        Next Row

    End With


End Sub


2 commentaires

Merci, erreur 1004! Cela a très bien fonctionné et j'ai appris de la structure de ce script. J'ai deux questions sur la façon de le modifier. Maintenant, au lieu d'être très spécifique et de nommer sampleA, sampleB, etc., comment puis-je dire au script de simplement lire la colonne A sous forme de chaîne? Existe-t-il un moyen que je puisse simplement appeler ces chaînes "sampleX" afin que je puisse parcourir une énorme feuille de calcul sans spécifier? Avec cela, puis-je faire une boucle jusqu'à la fin de la feuille de calcul pour dire "bonjour", par exemple, chaque fois qu'il y a une chaîne différente? Merci merci!


Heureux d'entendre cela une aide! Oui, vous pouvez faire une boucle sur chaque ligne et changer "PreviousString = .Range (" A "& Row - 1) .Value" en "sampleX = .Range (" A "& Row - i) .Value" et jouer avec le code. Essayez-le et faites-moi savoir si vous avez besoin de plus d'aide.



1
votes
  1. Vous déclarez vos variables sampleA, B, C mais vous ne les définissez jamais, donc lorsque vous comparez ces trois variables, rien ne se passe.

  2. À l'intérieur de votre boucle, vous ne définissez jamais ActiveCell sur quoi que ce soit, donc ActiveCell reste ce qu'il est. Vous bouclerez pour toujours à cause de cela.

  3. Voici une réécriture qui n'est pas vraiment optimisée. Il y a certainement de meilleures façons de le faire (en utilisant une boucle for sur la Range ("A1: A" & lastFilledRow) par exemple), mais je voulais garder cela assez proche de votre tentative de voir comment pour résoudre ce problème comme vous l'aviez prévu, car c'est certainement une manière viable et raisonnable de le faire.

    J'ai ajouté une tonne de commentaires pour expliquer ce qui se passait.

    Sub DoUntilStringMacro()
    
        Dim currentValue As String
        Dim previousValue As String
        Dim classification As String
    
        'set the first cell to search and we will iterate
        '   from there
        Dim searchCell As Range
        Set searchCell = Sheet1.Range("A2")
    
        'Lets also get a counter variable to see how many
        '   times we've found a change...
        Dim changesFound As Integer
    
        'Loop until the searchCell is empty
        Do Until searchCell.Value = ""
    
    
            'set the currentValue
            currentValue = searchCell.Value
    
            'If the previousValue variable is empty then
            '   this is the first cell we're analyzing
            '   so don't bother running this bit of code
            '   that does the comparison
            If previousValue <> "" Then
    
                'Compare to what we stored in previousValue
                If currentValue <> previousValue Then
                    'We found a change, increment our counter
                    changesFound = changesFound + 1
    
                    'and based on that value lets figure out
                    '   what to write out
                    Select Case changesFound
                        Case 1
                            'This is the first time we hit a
                            '   a change so write out "hello"
                            'BUT!!! we need to write it the
                            '   cell above the current
                            '   searchCell and one column over
                            '   We'll use .Offset() to do that
                            searchCell.Offset(-1, 1).Value = "Hello"
                        Case 2
                            searchCell.Offset(-1, 1).Value = "goodbye"
                        Case 3
                            searchCell.Offset(-1, 1).Value = "see you soon"
                    End Select
    
                End If
            End If
    
            'So we are going to iterate again, lets capture
            '   the currentValue into the previousValue
            '   variable so we have it to compare on the
            '   the next loop
            previousValue = currentValue
    
            'Also... we want to make sure that searchCell
            '   is the next cell otherwise we will just
            '   keep testing the same cell over and over
            '   again until excel crashes.
            'Again we'll use `.Offset()` to move to the
            '   next row
            Set searchCell = searchCell.Offset(1)
    
        Loop
    
        'Heres the kicker... we needed one more iteration
        '   since we exited when the searchCell was blank... 
        '   so that Case 3 never hit... 
        '   we'll just go ahead and fill that out now
        searchCell.Offset(-1, 1).Value = "See you soon"
    
    End Sub
    

    J'ai éliminé ActiveCell depuis ce n'est pas une bonne idée. Sélectionnez , Activer , ActiveCell ce sont toutes des photos de merde dans VBA. Il est préférable de dire "explicitement cette cellule / plage est ce que je veux" plutôt que d'espérer que la cellule que vous souhaitez est actuellement active.


6 commentaires

Merci pour cet indice, JNevill! J'aime l'apparence de ce script et je comprends jusqu'à certains points. Ma première question est: une fois que nous avons mis ce compteur à chaque fois qu'il y a un changement, ces entiers 1, 2, 3, etc. remplaceront la colonne A? Il semble que vous n'ayez jamais défini de colonne pour ces éléments. Ma deuxième question est la suivante: pourrions-nous ajouter à la colonne suivante, C, une formule pour uniquement les lignes contenant un entier? Et ma troisième question est: j'obtiens une erreur à currentValue = searchCell.Value. Pourquoi est-ce? Merci beaucoup!


1) Nous définissons une colonne en utilisant ce offset (-1,1) . Cela signifie monter sur la ligne à partir de la cellule actuelle et sur une colonne. 2) Je ne vous suis pas sur votre utilisation de la colonne C . "Seulement les lignes qui ont un entier" mais je ne vois aucun entier dans vos données ou les données que nous écrivons dans la colonne B . 3) Quelle est l'erreur que vous obtenez? Cliquez également sur le bouton "Déboguer" pour que la ligne soit mise en surbrillance et survolez searchCell.Value et voyez quelle valeur il rapporte dans cette cellule. Cela peut donner quelques indices (à côté du message d'erreur, ce qui est encore plus important)


Merci pour la réponse rapide. 1) Donc offset (-1,1) se trouve dans la ligne changesFound = changesFound + 1 ? 2) Oui, vous avez raison. Je voulais dire toutes les lignes de la colonne B qui ont maintenant une chaîne, bonjour, au revoir, etc., et pour que le script reconnaisse qu'il y a une chaîne là-bas et applique une formule à ces chaînes à afficher dans la colonne C. 3) Les états d'erreur qu'il y a un problème avec la gamme.


changesFound est juste une variable que nous incrémentons. La valeur de cette variable est contenue uniquement dans cette variable et nous ne l'écrivons jamais nulle part. Cependant, en utilisant l'instruction SELECT CASE , nous écrivons une chaîne dans la colonne B en utilisant Offset (1, -1) .value = "somestring" . Je suppose que vous pouvez mettre ce que vous voulez dans la colonne C. Si vous voulez le faire dans VBA, vous pouvez simplement ajouter searchCell.Offset (-1, 2) .value = "Ceci est la colonne C, et la colonne B est actuellement peuplé! ". Toujours pas sûr de cette erreur. Y a-t-il un numéro d'erreur associé?


D'accord, je vois. Nous pouvons insérer Offset (1, -1) .value = "somestring" après l'instruction Do Until? Pareil avec celui qui contrôle la colonne C? Il semble que l'erreur d'exécution exacte soit: '-2147417848 (80010108)': la méthode 'Value' de l'objet 'Range' a échoué et elle pointe vers currentValue = searchCell.Value


J'ai découvert mon erreur pour l'erreur. Merci encore :)



0
votes

Vous pouvez utiliser des formules et éviter les boucles:

Sub IdentifySampleNameChanges()
    With Worksheets("Sheet1") ‘ change “Sheet1” to your actual sheet name
          With .Range("A2", .Cells(.Rows.Count, "A").End(xlUp)).Offset(, 1)
             .Formula = "=IF(A2<>A3,""Hello"","""")"
             .Value = .Value
        End With 
    End With 
End Sub


2 commentaires

C'est génial. Je vous remercie! Pour ajouter à cela, comment appliquer une formule à toutes les valeurs sampleA, sampleB, etc. au-dessus de chaque bonjour?


Je vous en prie. Si ma réponse a résolu votre question originale , vous pouvez envisager de la marquer comme acceptée. Je vous remercie. En ce qui concerne la "formule au-dessus de chaque bonjour", vous voudrez peut-être donner plus de détails