Bonjour,
Comme chacun sait, Excel et VBA ont des spécifications, limites et lacunes.
En ce qui concerne Excel, je ne vais pas les lister dans le sens ou c'est très bien fait ICI, du moins pour ce qui concerne les versions postérieures à 2007.
Vous trouverez ICI les limites de chaque type de données (Byte, Integer, Long, Currency, String,...).
Nous allons, dans ce sujet (re)découvrir et tenter de lister et résoudre un maximum de celles de VBA.
Etant persuadé en avoir oublié, n'hésitez pas à me les indiquer en réponse pour que ce sujet soit le plus exhaustif possible.
________________________________________________________________________________________________________________
- Le nombre maximum d'Areas dans une feuille
- Limite
Ce nombre maximum est fixé à 8 192.
Ce nombre correspond à la moitié de la limite de la méthode SpecialCells (cf plus bas) qui, vous en conviendrez, est fortement liée à la notion d'Areas.
A noter toutefois que ce nombre semble s'augmenter au fur et à mesure des tests, Excel "réagissant" en effet sur ce sujet afin de s'adapter à la demande de l'utilisateur.
Ainsi, un même utilisateur, sur un même pc, sans toucher à l'installation d'Office, peut voir ce maximum considérablement s'agrandir...
Cela reste, pour moi, un des mystères de MS Excel.- Comment y pallier
cf paragraphe ci-dessous, à propos de la méthode SpecialCells.
- Limite de la méthode SpecialCells
- Limite
Elle ne peut recenser d'un seul coup plus d'un certain nombre d'aires (Areas) résultant de son application.
Ce nombre est égal à la moitié de la limite d'un type integer soit 16 385.- Comment y pallier
Lire la contribution d'unparia à ce sujet
- Le nombre maximum d'éléments dans un Array
Ce nombre est limité par la quantité de mémoire disponible.
Il varie donc selon le type de données contenues dans cet Array.
C'est pourquoi il est toujours vivement recommandé de bien typer toutes vos variables.
- La division entière : \
- Limite
Le plus grand nombre que l'on puisse diviser grâce à l'opérateur \ est 2 147 483 647.
Il correspond à la limite du type Long.- Test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 Sub Demo_Division_Entiere() Dim d As Double, i As Double d = 2147483647 MsgBox d \ 83647 d = 2147483648# On Error Resume Next MsgBox d \ 2 If Err.Number > 0 Then MsgBox Err.Description On Error GoTo 0 End Sub- Comment y pallier
Il suffit, pour cela, de prendre la partie entière de la division de deux Doubles.
Voici une fonction qui fait très bien l'affaire, à titre d'exemple :
Code appelant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Function Division_Entiere(Nb1 As Double, Nb2 As Double) As Double Division_Entiere = Int(Nb1 / Nb2) End Function
Code : Sélectionner tout - Visualiser dans une fenêtre à part MsgBox Division_Entiere(21474836489#, 12542)- A noter :
VBA n'étant pas très bien armé pour les opérations sur de grands nombres, la division de deux Double peut générer des erreurs...
- Le Modulo : Mod
- Limite
L'opérateur Mod est limité à 2 147 483 647.
Il correspond à la limite du type Long, tout comme pour la division entière.- Test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 Sub Demo_Mod() Dim d As Double d = 2147483647 MsgBox d Mod 83647 d = 2147483648# On Error Resume Next MsgBox d Mod 2 If Err.Number > 0 Then MsgBox Err.Description On Error GoTo 0 End Sub- Comment y pallier
Tout comme pour la division entière, avec une petite fonction perso. Exemple :
Code appelant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Function ModSansLimite(Nb1 As Double, Nb2 As Double) As Double ModSansLimite = Nb1 - (Int(Nb1 / Nb2) * Nb2) End Function
Code : Sélectionner tout - Visualiser dans une fenêtre à part MsgBox ModSansLimite(2147483648, 83647)
- La méthode WorksheetFunction.Match
- Limite
La limite de cette méthode est de 65 536.
Ce nombre correspond à la limites de lignes dans Excel 2003.- Test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 Sub Demo_Match() Dim t() As String, v, var As String, i As Long var = "liste21" ReDim t(65535) For i = LBound(t) To UBound(t) t(i) = "liste" & i Next v = Application.Match(var, t, 0) MsgBox v ReDim Preserve t(65536) t(65536) = "liste65536" On Error Resume Next v = Application.Match(var, t, 0) If Err.Number > 0 Then MsgBox Err.Description On Error GoTo 0 End Sub- Comment y pallier
Par une fonction personnelle.
Cette fonction perso va utiliser une fonction qui détermine le nombre de dimensions d'un Array (Function Nb_Dimensions).
Fonction Nb_Dimensions (utile également dans le paragraphe sur Transpose (ci-dessous)) :
La fonction de "remplacement" de Match :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 Function Nb_Dimensions(ByRef Tableau As Variant) As Integer 'Retourne le nombre de dimensions d'une variable tableau Dim d As Integer, t As Long On Error GoTo Fin Do d = d + 1 t = UBound(Tableau, d) Loop Fin: On Error GoTo 0 Nb_Dimensions = d - 1 End Function
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 Function Get_Row(ByRef Tableau As Variant, ByRef Texto As Variant, Optional ByRef Colonne As Long) As Long 'Détermine l'index d'un élément à partir de son contenu 'Retourne un Long représentant l'index de cet élément 'Retourne -1 si l'élément n'existe pas dans le tableau ou erreur (de colonne, de Tableau, etc). Dim i As Long, strTemp As String Get_Row = -1 Select Case Nb_Dimensions(Tableau) Case 1 '===== le présent code, déposé par ucfoutu sur VBFrance, est la seule propriété de VBFrance '=====VBFrance en autorise les libres copie et utilisation à la seule condition d'y laisser '=====insérées les trois présentes lignes commentées --- ucfoutu --- strTemp = Chr(0) & Join(Tableau, Chr(0)) & Chr(0) i = InStr(strTemp, Chr(0) & Texto & Chr(0)) If i = 0 Then Get_Row = -1 Else strTemp = Mid(strTemp, 1, i) Get_Row = UBound(Split(strTemp, Chr(0))) - 1 If Get_Row < 0 Then Get_Row = -1 End If '====================== Case 2 'si paramètre colonne omis, on prends la première If Colonne = 0 Then Colonne = LBound(Tableau, 2) For i = LBound(Tableau, 1) To UBound(Tableau, 1) If Tableau(i, Colonne) = Texto Then Get_Row = i: Exit For Next i End Select End Function- A noter :
La même limite est fixée en ce qui concerne la fonction Index (WorksheetFunction.Index).
Il est cependant beaucoup plus simple d'y remédier...
- La méthode Transpose
- Limite
La limite de cette méthode est de 65 536.
Tout comme Match et Index, ce nombre correspond à la limite de lignes dans Excel 2003.- A noter :
Transpose, étant à la base une fonction de feuille de calcul, retourne un Array en Base 1 même si l'Array qui lui est injecté est en Base 0.
Notre fonction pour pallier à la limite de Transpose palliera également à cela.- Test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 Sub EssaiTranspose() Dim t() As String, v, i As Long ReDim t(2, 65535) For i = LBound(t) To UBound(t) t(1, i) = "liste" & i Next v = Application.Transpose(t) MsgBox "Avec TRANSPOSE, cas < 65 536" & vbCrLf & vbCrLf & _ "t : " & LBound(t, 1) & " To " & UBound(t, 1) & " <=> " & LBound(t, 2) & " To " & UBound(t, 2) & vbCrLf & _ "v : " & LBound(v, 1) & " To " & UBound(v, 1) & " <=> " & LBound(v, 2) & " To " & UBound(v, 2) Erase v ReDim Preserve t(2, 66000) For i = 65536 To 66000 t(1, i) = "liste" & i Next i On Error Resume Next v = Application.Transpose(t) If Err.Number > 0 Then MsgBox "Avec TRANSPOSE, cas > 65 536" & vbCrLf & vbCrLf & Err.Description On Error GoTo 0 End Sub- Comment y pallier
Il nous faut une fonction personnalisée qui :
> transpose l'array
> le restitue dans la même base
Exemple (Attention : utilise la fonction Nb_Dimensions cf paragraphe précédent) :
Code appelant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 Function Transposition(ByRef Tableau As Variant) As Variant 'Transpose une variable tableau à 2 dimensions Dim tabl, i As Long, j As Long, c As Long Select Case Nb_Dimensions(Tableau) Case 1 c = LBound(Tableau) c = IIf(c = 0, 1, 0) ReDim tabl(1 To UBound(Tableau) + c, 1 To 1) For i = 1 To UBound(tabl) tabl(i, 1) = Tableau(i - c) Next Case 2 ReDim tabl(LBound(Tableau, 2) To UBound(Tableau, 2), LBound(Tableau, 1) To UBound(Tableau, 1)) For i = LBound(Tableau, 1) To UBound(Tableau, 1) For j = LBound(Tableau, 2) To UBound(Tableau, 2) tabl(j, i) = Tableau(i, j) Next j Next i Case Else MsgBox "Le tableau ne comporte pas une ou deux dimensions" Exit Function End Select Transposition = tabl Erase tabl End Function
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 Dim t() As String, v, i As Long ReDim t(2, 66666) For i = LBound(t) To UBound(t) t(1, i) = "liste" & i Next v = Transposition(t) MsgBox "Avec Transposition, cas > 65 536" & vbCrLf & vbCrLf & _ "t : " & LBound(t, 1) & " To " & UBound(t, 1) & " <=> " & LBound(t, 2) & " To " & UBound(t, 2) & vbCrLf & _ "v : " & LBound(v, 1) & " To " & UBound(v, 1) & " <=> " & LBound(v, 2) & " To " & UBound(v, 2)- Limite de la méthode Union
- Lacunes
Deux lacunes sont à déplorer au sujet de cette Méthode :
> Si un des arguments = Nothing elle engendre une erreur Argument ou appel de procédure incorrect
> Si deux Range s'intersectent, leurs cellules communes sont comptabilisées 2 fois.- Test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 Sub Demo_Union() Dim Rng As Range, R As Range On Error Resume Next Set Rng = Application.Union(R, Range("A8:C10"), Range("B9:D11")) If Err.Number > 0 Then MsgBox Err.Description On Error GoTo 0 Set Rng = Application.Union(Range("A8:C10"), Range("B9:D11")) MsgBox Rng.Address & " " & Rng.Cells.Count End Sub- Comment y pallier
Avec cette fonction :
Code appelant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 Function UnionSansDoublons(ParamArray Rngs() As Variant) As Range Dim RngTemp As Range, R As Range, i As Long For i = LBound(Rngs) To UBound(Rngs) If Not Rngs(i) Is Nothing Then If RngTemp Is Nothing Then Set RngTemp = Rngs(i) Else For Each R In Rngs(i).Cells If Application.Intersect(RngTemp, R) Is Nothing Then Set RngTemp = Application.Union(RngTemp, R) End If Next R End If End If Next i Set UnionSansDoublons = RngTemp End Function
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Dim Rng As Range, R As Range Set Rng = UnionSansDoublons(R, Range("A8:C10"), Range("B9:D11")) MsgBox Rng.Address & " " & Rng.Cells.Count
________________________________________________________________________________________________________________
Il existe encore moultes autres limites et ou lacunes.
Par exemple : la limite de lignes dans un module est fixée à 65 531 (en tout cas chez moi)...
Je compte sur vous...
Merci
Partager