Longueur de la variable String [VBA]

Résolu/Fermé
JPKOF - Modifié par JPKOF le 13/10/2010 à 10:54
 JPKOF - 14 oct. 2010 à 15:31
Bonjour à tous,

Je vous expose mon problème :
Dans une feuille de calcul que je reçois chaque semaine, il y a certaines lignes pour lesquelles la valeur de la case (i , 1) est nulle (ou vide).
Je voudrai supprimer toutes ces lignes.
J'ai bien trouvé une solution avec un :

nblig = Range("a65535").End(xlUp).Row 
For i = 2 To nblig 
    If Cells(i, 1) = 0 Or Cells(i, 1) = "" Then 
    Cells(i, 1).Delete Shift:=xlUp 
    End If 
Next i


Oui ça marche mais c'est trés trés long. Mon fichier faisant entre 60 000 et 65 000 lignes j'ai donc cherché une autre solution un peu plus compliquée (mais qui ne marche pas ... encore :p ) et surtout plus rapide dans l'éxécution :

Dim zonasup as string 
nblig = Range("a65535").End(xlUp).Row 
zonasup = "" 
For i = 2 To nblig 
    If Cells(i, 1) = 0 Or Cells(i, 1) = "" Then 
         If zonasup ="" then 
                zonasup = i & ":" & i 
         else: zonasup = zonasup & "," & i &":" & i 
         end if 
    End If 
Next i 
range(zonasup).Delete Shift:=xlUp 


L'idée est donc de stocker tous les numéros de lignes à supprimer pour pouvoir tout supprimer en une seule étape à la fin.
Cependant, lorsque je fais tourner la macro, ça plante justement à la ligne
range(zonasup).Delete Shift:=xlUp

Et lorsque je regarde le contenu de ma variable zonasup à ce moment la (via un espion) je tombe sur

"86:86,87:87,88:88,89:89,90:90,91:91,92:92,93:93,94:94,95:95,96:96,97:97,230:230,231:231,232:232,233:233,234:234,235:235,236:236,237:237,238:238,239:239,240:240,241:241,327:327,328:328,329:329,330:330,331:331,332:332,333:333,334:334,336:336,337:337,33


Le point positif c'est que le contenu de la variable est écrit de la façon que je voulais, le point négatif c'est que cette variable ne semble stocker que 250 caractères (j'ai testé de copier coller dans une cellule excel et j'ai fait un NBCAR(...))
Le problème vient-il de la taille maximale de la variable string ?

J'espère avoir été suffisamment clair, peut être un peu trop pour quelque chose qui ne reste peut être, au fond, qu'un petit problème de string :)

3 réponses

eriiic Messages postés 24570 Date d'inscription mardi 11 septembre 2007 Statut Contributeur Dernière intervention 23 avril 2024 7 213
13 oct. 2010 à 11:13
Bonjour,

Tu peux rester sur ta 1ère solution et ajouter devant :
Application.ScreenUpdating = False
à rétablir à = True après

Et si tes cellules sont vraiment vides (pas de formule) tu peux le faire sans boucle avec :
Columns(1).SpecialCells(xlCellTypeBlanks).EntireRow.Delete

eric
1
Je n'ai donné que la partie du code qui concernait la suppression de lignes, j'ai effectivement oublié de signaler que j'utilisais application.screenupdating au début de la macro ainsi qu'à la fin. Mais même avec ceci l'éxécution se révèle excessivement longue.
Concernant les cellules "vraiment vides" : elles le sont vraiment et la fonction que tu me proposes marche donc bien.
Cependant la cellule avec formule pour lesquelles la veleur de la formule est nulle affichent "0"
je test une formule équivalent avec xlCellTypeNull mais ça ne marche pas :)
Merci pour ton aide
0
eriiic Messages postés 24570 Date d'inscription mardi 11 septembre 2007 Statut Contributeur Dernière intervention 23 avril 2024 7 213
Modifié par eriiic le 13/10/2010 à 12:31
Re,

Je n'avais pas rafraichi, salut michel, on est bien phase... :-)

xlCellTypeNull c'était bien tenté... ;-)

Après avoir supprimé les vides avec xlCellTypeBlanks je te propose d'utiliser le filtre automatique pour accelerer le traitement :
Cells.AutoFilter Field:=1, Criteria1:="0"
Rows("2:65536").Delete Shift:=xlUp
Selection.AutoFilter Field:=1

Je te laisse tester le gain sur un grand fichier, à toi de dire...

eric
0
michel_m Messages postés 16603 Date d'inscription lundi 12 septembre 2005 Statut Contributeur Dernière intervention 16 décembre 2023 3 303
13 oct. 2010 à 12:42
On va suivre dans l'ordre chronologique des messsages...

Donc, en guise d'apéro
temps pour 7500 lignes DonT 4100 vides ou 0: environ 0,9 secondes (512 mo de ram)
principe; je récolte les lignes non vides ou 0 dans un tableau-array et je restitue en supprimeant auparavant les données originelles

Const deplig As Byte = 2 'ligne de départ
Sub supprimer_ligne()
Dim derlig As Long, cptr As Long, cptr_t As Long
Dim tablo, valeur
derlig = Cells(Cells.Rows.Count, 1).End(xlUp).Row

'pour test rapidité
Start = Timer
ReDim tablo(8, 0)

For cptr = deplig To derlig
    valeur = Cells(cptr, 1)
    If valeur <> 0 Or valeur <> "" Then
        ReDim Preserve tablo(8, cptr_t)
        For col = 0 To 8
            test = Cells(cptr, col + 1)
            tablo(col, cptr_t) = Cells(cptr, col + 1)
        Next
         cptr_t = cptr_t + 1
    End If
Next

Application.ScreenUpdating = False
Range("A2:I" & derlig).ClearContents
Range("A2").Resize(cptr_t, 9) = Application.Transpose(tablo)
MsgBox Timer - Start & "secondes"
End Sub


Eric ta solution est astucieuse mais est ce que ca masque sans détruire les lignes vides (suis faché betement avec les filtres) ?
0
eriiic Messages postés 24570 Date d'inscription mardi 11 septembre 2007 Statut Contributeur Dernière intervention 23 avril 2024 7 213
Modifié par eriiic le 13/10/2010 à 13:09
est ce que ca masque sans détruire les lignes vides
Ca affiche les 0 et supprime ces lignes, les vides sont traités auparavant avec xlCellTypeBlanks .

J'ai testé sur 59400 lignes, tu es plus rapide (11s au lieu de 23s) mais il reste les 0 chez toi (???).
Il doit manquer qcq chose...

eric
0
eriiic Messages postés 24570 Date d'inscription mardi 11 septembre 2007 Statut Contributeur Dernière intervention 23 avril 2024 7 213
Modifié par eriiic le 13/10/2010 à 13:36
17.6s, je ne peux pas mieux avec cette technique :-)
Sub supprimerLig()  
    ' supprime ligne avec 0 ou vide en colonne A 
    Dim t As Double  
    Application.ScreenUpdating = False  
    t = Timer  
    Range("A1").AutoFilter  
    Range([A1], ActiveCell.SpecialCells(xlLastCell)).AutoFilter
    Cells.AutoFilter Field:=1, Criteria1:="=", Operator:=xlOr, Criteria2:="=0"  
    Rows("2:65536").Delete Shift:=xlUp  
    Selection.AutoFilter Field:=1  
    Application.ScreenUpdating = True  
    MsgBox (Timer - t)  
End Sub
0
michel_m Messages postés 16603 Date d'inscription lundi 12 septembre 2005 Statut Contributeur Dernière intervention 16 décembre 2023 3 303
Modifié par michel_m le 13/10/2010 à 11:14
Bonjour,

Sur 65000 lignes je ne garantis pas mais essaies:

range("A1:A65536").SpecialCells(xlCellTypeBlanks).EntireRow.Delete

t'enlève les celules vides (pas celles avec des 0)

je regarde pour un autre truc et te dis...

Combien as tu de colonnes dans ton tableau ?

d'ores et déjà yu gagnerais un temps important avec cette ligne en début de macro:
application.screenupdating=false

Michel
0
Tout d'abord merci pour ton aide.
Ta fonction marche bien sur 65000 lignes et est autrement plus rapide que ma boucle.
Je cherche actuellement un moyen de l'adapter pour les cellules de valeur égale à 0.
Mon tableau a 9 colonnes (et la ligne 1 est réservée pour les entêtes de colonnes :) )
0
michel_m Messages postés 16603 Date d'inscription lundi 12 septembre 2005 Statut Contributeur Dernière intervention 16 décembre 2023 3 303
13 oct. 2010 à 12:13
re et bonjour Eriic

merci pour les 9 colonnes, ca va permettre de feinter!

je te propose un truc dès que possible
0
Bilan : ça marche trés bien,

Cependant, quitte à apprendre quelque chose aujourd'hui j'aurai quelques questions :

Quelle est la différence entre
derlig = Cells(Cells.Rows.Count, 1).End(xlUp).Row

et
derlig = Range("f65535").End(xlUp).Row


Que comprends VBA lorsqu'on appelle les varaibles
DIM tablo, valeur


Pourquoi stocker les valeurs dans la variable tablo en inversant les lignes et les colonnes ?

Par ailleurs, la macro marche mais des lignes vides apparaissent dorénavant en première position. Est ce normal ?
0
michel_m Messages postés 16603 Date d'inscription lundi 12 septembre 2005 Statut Contributeur Dernière intervention 16 décembre 2023 3 303
Modifié par michel_m le 13/10/2010 à 17:50
1/ les 2 formules sont valables. mais comme XL2007 a plus d'un million de lignes, la 1° formule marche sur les versions 2007 et inférieure (comme tu travailles sur 65000 lignes on aurait pu écrire
Range("A65536")..).

2/ Dim tablo, valeur ==> variant
je connaissais pas le type des données en colonne A: toi,si, donc tu peux complèter.
pour le tablo je laisse toujours en variant car le type des données est variable;dans le 1° paramêtre(8,0) 1° rang peut -être en string, le 2° en single le 3° en date...

3/ je ne sais pas combien de lignes va avoir le tableau puisqu'à chaque condition remplie j'augmente 1 ligne au nombre de lignes par redim preserve tablo (8,cpr_t)...... cpr_t=cpr_t+1
Or on peut faire cela que sur le dernier paramêtre, d'où l'inversion lignes colonnes, d'où ensuite l'utilisation de la fonction Excel "transpose"

4/ lignes vides: sur ma maquette le n'ai pas ce problème. attention si tu as fait des adaptations à la réalité de ton classeur, des oublis ou maladresses (on sait tous faire) font des trucs tout drôles ou il ya le résultat d'une formule qui renverrait "" et peut-être que...


Les variables- tableaux sont indispensables lorsque tu as des tableaux géants comme les tiens car on quitte les feuilles XL (va et vient ecran, mémoire, processeur, mémoire, ecran) pour travaille en mémoire ram et peut ^tre en L2

Si ca t'intéresse, tu as un tuto très pédagogique écrit pas mon vieux copain Silkyroad sur Developpez.Com
https://silkyroad.developpez.com/vba/tableaux/

enfin, tu ne peux peut-être pas faire autrement mais Microsoft déconseille les databases XL de plus de 15000 lignes
http://office.microsoft.com/fr-ch/excel-help/utilisation-d-access-ou-d-excel-pour-gerer-vos-donnees-HA001042918.aspx
mais bof!

Voilà, je vais quand m^me regarder pour les lignes et je te fais signe si il y a un bug... sinon, bonne soirée et content pour toi si t'es débarrassé de ce problème
Cordialement
0
Merci beaucoup pour toutes ces informations.
J'ai vraiment cherché comment apparaissaient ces lignes vides.
A défaut de pouvoir prévenir, j'ai réussi a guérir en utilisant la formule que vous m'aviez donné en début de post, à savoir :
Columns(1).SpecialCells(xlCellTypeBlanks).EntireRow.Delete 


DU coup le résultat obtenu est celui attendu dans un temps record (en ajoutant votre code à la suite du mien j'obtiens une macro qui tourne en moins de 30 sec).

Merci à tout les deux pour votre aide et à la prochaine
0