Array(Split : passe un Array dans le ref(0).
ref est donc un Array dont le premier Item, ref(0) est lui même un Array. Tu le vois en observant ref(0)(1) par exemple.
Comme ref(0) est un Array, il a un Ubound.
Version imprimable
Array(Split : passe un Array dans le ref(0).
ref est donc un Array dont le premier Item, ref(0) est lui même un Array. Tu le vois en observant ref(0)(1) par exemple.
Comme ref(0) est un Array, il a un Ubound.
hoh!! puré coup de trique que je merite j'ai meme pas fait attention a ca "array"
bon je vais regarder ca
mille excuses faute d'inatention
voir si j'ai bien compris
tu créé un array de 1 item dans le quel tu met le split donc un tablo
tu redim ref au nombre du tableau dans son item 0 et en variant
et tu met dans chaque item la valeur de l'index du tableau dans l'item 0 tu commence bien entendu par le 2d item donc le (1) pour gartder les valeurs jusqu'a fin de deplacement des valeurs
il fallait aller la pecher celle la respect
en ce qui concerne l'allocation de memoire je ne suis pas sur qu''il n'y ai pas d'incidence le ref n'est plus le meme apartir de redim (a verifier)
Tu as bien compris.
Pour l'allocation de mémoire, bien sûr que ref tient plus de place après ReDim. Par contre, comme on re-alloue, à ref, un nouvel espace, il n'est plus "figé" en String.
Car déjà ref = [{1,2,3,4}] crée une matrice d'éléments numériques …
Ensuite s'il faut travailler comme ici à partir d'une p'tite chaine avec un délimiteur différent
Evaluate évite de boucler soit via Split & Join soit directement via Replace …
Je te l'ai pourtant expliqué dans le post #27, message créé spécialement à ton intention présentement !
Mais bon, mieux vaut tard que jamais …
re
oui marc j'ai vu apres mille excuses en relisant le post complet pour mes archives
apres test effectivement evaluate bien que plus simple visiblement est 2 fois (voir plus/lent ) plus lourd c'est incontestable
comme quoi les idées recu (preférer les fonctions excel à vba) pour une fois c'est vba qui l'emporte haut la main
je suprime neanmoins 1 ligne de code on reste en lbound/ubound mais en bouclant simplement a l'envers le premier item etant gardé en tant que tableau tant que l'on y est pas arrivé;)
Code:
1
2
3
4
5
6
7
8
9 Sub Demo() Dim ref, i& ref = Array(Split("1,2,3,4,5,6,7,8,9", ",")) ReDim Preserve ref(0 To UBound(ref(0))) For i = UBound(ref) To 0 Step -1 ref(i) = CLng(ref(0)(i)) Next i MsgBox ref(0) End Sub
Jacques,
J'ai loupé ta dernière réponse.
Oui un bon code ne se compte pas au nombre de ses lignes, mais à son efficacité. Ici celle d'Evaluate reste à démontrer.
Patrick,
Evaluate est plus lente uniquement en cas de petite chaîne en entrée. Si tu testes avec une chaîne de 2-3000 caractères, ce n'est plus pareil. De plus, des trois solutions, la plus fiable reste le transfert dans un tableau de Long, à mes yeux.
Marc,
Oui tu as raison. Néanmoins, Evaluate reste limitée à ce qu'elle est censée trouver dans une cellule, une chaîne avec un nombre limité de caractères. Je tenais juste à souligner cette limite.
A++
Euh ... Chez moi (Excel 2007) evaluate n'est pas une fonction Excel, mais une méthode VBACitation:
apres test effectivement evaluate bien que plus simple visiblement est 2 fois (voir plus/lent ) plus lourd c'est incontestable
comme quoi les idées recu (preférer les fonctions excel à vba) pour une fois c'est vba qui l'emporte haut la main
Pour conclure :
la méthode Evaluate est instantanée pour une pauvre matrice de 4 éléments tel posée dans la demande initiale ‼
Bonjour à tous,
Franck :plusser: pour ton post # 20, bien vu
Comme pour tout, choisir la méthode à utiliser selon les conditions, dans certains cas Evaluate sera plus favorable alors que dans d'autre cas non …
Exemple d'Evaluate utile parmi d'autres:
Après le choix appartient au codeur …Code:
1
2
3 With Feuil1.[A1].CurrentRegion.Rows VA = Application.Index(.Value, Evaluate("ROW(3:" & .Count & ")"), [{5,8,11}]) End With
Bonsoir,
J'ai essayé de voir si j'arrivais à trouver une autre méthode (difficile vu les réponses déjà données), à défaut je vais mettre une autre façon de l'écrire;
Utilisation de la boucle For Each (plus rapide normalement) et de la conversion CLng (sans la conversion CLng, au lieu du Long on a du Double) :
Code:
1
2
3
4
5
6
7
8 Sub TestRyu_Long() Dim Ref0$, Ref1, V Ref0 = "1:2:3:4" ReDim Ref1(1 To (Len(Ref0) + 1) / 2) For Each V In Split(Ref0, ":") i = i + 1: Ref1(i) = CLng(V) Next End Sub
Edit : * 1 supprimer pour le LongCode:
1
2
3
4
5
6
7
8 Sub TestRyu_Double() Dim Ref0$, Ref1, V Ref0 = "1:2:3:4" ReDim Ref1(1 To (Len(Ref0) + 1) / 2) For Each V In Split(Ref0, ":") i = i + 1: Ref1(i) = V * 1 Next End Sub
Bonjour ryu,
tu peux te passer du *1, toujours un petit pouième de gagné :-)
Mais je ne venais pas pour ça...
Par curiosité je me suis laissé aller à des variations, et je me suis aperçu d'une chose sur laquelle je n'aurais pas parié :
4 mid() est 2 fois plus plus rapide qu'1 split()
J'ai laissé V en variant pour ne pas fausser.
ericCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 Sub TestRyu_Long2() Dim Ref0$, Ref1, V, i As Long, j As Long Dim t As Single Ref0 = "1:2:3:4" ReDim Ref1(1 To (Len(Ref0) + 1) / 2) t = Timer For j = 1 To 100000 i = 0 For Each V In Split(Ref0, ":") i = i + 1: Ref1(i) = CLng(V) Next Next j Debug.Print Timer - t '0.38 t = Timer For j = 1 To 100000 i = 0 For V = 1 To 7 Step 2 i = i + 1: Ref1(i) = CLng(Mid(Ref0, V, 1)) Next Next j Debug.Print Timer - t '0.20 End Sub
salut Eric,
En effet tu as raison pour le *1 pour le Long ;) (je l'avais mis au début avec un résultat en Double, j'aurais du l'enlever pour le Long :oops:)
j'y ai pensé au Mid mais j'étais pas inspiré :oops:, bien vu :plusser: , dans tous les cas je trouvais intéressant de s'y prendre de cette façon.
Avec le Mid, on divise quasi par 2 le temps de la boucle
je crois déjà avoir entendu dans différents cas que Mid, Instr … étaient plus rapide (surement mon senseï :D ;))Citation:
Par curiosité je me suis laissé aller à des variations, et je me suis aperçu d'une chose sur laquelle je n'aurais pas parié :
4 mid() est 2 fois plus plus rapide qu'1 split()
En testant ton code voilà le résultat sur ma machine :
• 0,3613281 (For Each)
• 0,1523438 (Mid)
Par contre ton code pour le Mid est dans un cas simple, que fais tu dans cette situation :
=> "100:2:3241:452:60"
• pb de Redim
• pb de Step dans la boucle
• pb sur le Mid aussi
=> Une Solution :
Edit : On pourrait même en faire une fonction pour remplacer dans certains cas le split ;)Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 Sub TestRyu_Long3() Dim Ref0$, Ref1, j&, i&, x&, y&, T! Ref0 = "1:2:3:4" ReDim Ref1(1 To Len(Ref0) - Len(Replace(Ref0, ":", "")) + 1) T = Timer For j = 1 To 100000 i = 0 For x = 1 To Len(Ref0) y = InStr(x, Ref0, ":"): If y = 0 Then y = Len(Ref0) + 1 i = i + 1: Ref1(i) = CLng(Mid(Ref0, x, y - x)) x = y Next Next Debug.Print Format(Timer - T, "0.000 s") ' entre 0.166 s et 0.168 s sur mon Mac (surement plus rapide sur PC) End Sub
Bonjour Ryu
Largement réalisable, mais plus long si l'on utilise la fonction Mid --->>Citation:
On pourrait même en faire une fonction pour remplacer dans certains cas le split
On économiserait un peu de temps en utilisant la fonction strconv plutôt que Mid, mais même ainsi, ce serait plus lent que la fonction Split.Code:
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
30
31
32
33
34
35
36
37 Private Sub CommandButton1_Click() Dim toto As String toto = "100:2:3241:452:60" deb = Timer For I = 1 To 100000 T1 = aaSplit(toto, ":") Next MsgBox Timer - deb deb = Timer For I = 1 To 100000 T2 = Split(toto, ":") Next MsgBox Timer - deb For I = 0 To UBound(T1) MsgBox T1(I) & " " & T2(I) Next End Sub Public Function aaSplit(ByVal ch As String, ByVal S As String) As Variant Dim pos As Long, saut As Byte saut = Len(S) Dim T() As String ReDim T(0) pos = InStr(ch, S) If pos = 1 Then '------>> juste pour le cas où commencerait par le séparateur ch = Mid$(ch, saut + 1) pos = InStr(ch, S) End If While pos > 0 T(UBound(T)) = Left(ch, pos - 1) ch = Mid$(ch, pos + saut) ReDim Preserve T(UBound(T) + 1) pos = InStr(ch, S) Wend T(UBound(T)) = ch aaSplit = T End Function
Bonjour,
Oui l'appel à une fonction personnalisée, qui n'est pas neutre, handicape beaucoup.Citation:
Largement réalisable, mais plus long si l'on utilise la fonction Mid
Reste qu'en cas de très gros volume le passage de split() à mid(), au prix de qq lignes de code en plus et en restant dans la procédure, mérite qu'on s'interroge sur le choix à faire.
Mid() se devait d'être optimisée au maximum, effort qu'ils n'ont apparemment pas fourni pour split().
Utilisable dans la majorité des cas, c'est quand même bien qu'elle existe pour simplifier :-)
eric
Petite manière rigolote d'obtenir directement un tableau de longs sans split (avec left et Mid)
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 toto = "100:2:3241:452:60" ReDim tb(Len(toto) - Len(Replace(toto, ":", ""))) As Long For i = 0 To UBound(tb) pos = InStr(toto, ":") If pos = 0 Then tb(i) = toto: Exit For tb(i) = Val(Left(toto, pos - 1)) toto = Mid(toto, pos + 1) Next '------------Preuve ------------------------ For i = 0 To UBound(tb) MsgBox tb(i) & " " & TypeName(tb(i)) Next
Jacques,
Une fois n'est pas coutume. .. :plusser:
Par contre, tu disais pouvoir remplacer Mid par StrConv. Je suis curieux de voir ça... j'ai encore du mal avec ces tableaux de byte...
Merci d'avance.
Amitiés.
Bonsoir les codeurs:D,
PS : Salut Franck : t'as oublié de cliquer sur le :plusser: du post #55, Jacques va croire que tu l'as fait 8-) ;)
Coucou Jacques,
pas beaucoup de temps aujourd'hui, donc me revoilà …
PS : n'aurais tu pas modifier ton message du post #53 ? il me semblait avoir lu un truc du genre : "que fais tu si il y a ":" au début (1è position) du texte ?" - à moins que j'ai révé :ptdr:
PS : Déjà merci de partager tes idées de codes/démos => :plusser: pour le post #53 et 55 (le 55 remarquable niveau performance)
• Du coup j'ai poussé le vice en compliquant la situation (sait t-on jamais …) en mettant : ":100:2:3241::452:60:"
Donc j'ai revu mond code (pas super beau mais ca marche) :
Comme tu le dis pour une fonction : "Largement réalisable, mais plus long"Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 Sub TestRyu_Long5() Dim Ref0$, Ref1, j&, i&, x&, poS As Byte, T! Ref0 = ":100:2:3241::452:60:" ReDim Ref1(1 To Len(Ref0) - Len(Replace(Ref0, ":", "")) + 1) T = Timer For j = 1 To 100000 i = 0 For x = 1 To Len(Ref0) poS = InStr(x, Ref0, ":"): If poS = 0 Then poS = Len(Ref0) + 1 Else If poS = x Then x = x + 1: poS = InStr(x + 1, Ref0, ":") i = i + 1: Ref1(i) = CLng(Mid(Ref0, x, poS - x)) x = poS Next ReDim Preserve Ref1(1 To i) Next Debug.Print Format(Timer - T, "0.000 s") End Sub
Mais peut être valable dans un procédure comme le dit Eric ;) (à voir …)
• le post #55 :
j'ai adoré ce code et je me suis demandé comment allié la situation ci-dessus avec ton code, voilà le résultat :
• moi aussi je suis curieux pour le StrConv, mais je vais tenter de faire un code j'ai une petite idée la dessus :DCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 Sub unparia2() toto = ":100:2:3241::452:60:": toto = Application.Trim(Replace(toto, ":", " ")) ReDim tb(Len(toto) - Len(Replace(toto, " ", ""))) As Long T = Timer For j = 1 To 100000 For i = 0 To UBound(tb) poS = InStr(toto, " ") If poS = 0 Then tb(i) = toto: Exit For tb(i) = Val(Left(toto, poS - 1)) toto = Mid(toto, poS + 1) Next Next Debug.Print Format(Timer - T, "0.000 s") End Sub
Bonjour, Franck et Ryu
Oh. Le strconv ? --->> rien d'intéressant ni de "transcendantal" --->> mais voilà --->>
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 toto = "100:2:3241:452:60" S = Asc(":") Dim titi() As Byte ReDim tb(Len(toto) - Len(Replace(toto, ":", ""))) As Long titi = StrConv(toto & ":", vbFromUnicode) For k = 0 To UBound(titi) '- 1 If titi(k) <> S Then ch = ch & Chr(titi(k)) Else tb(n) = Val(ch): ch = "": n = n + 1 End If Next '-----------------preuve For k = 0 To UBound(tb) MsgBox tb(k) & " " & TypeName(tb(k)) Next
Re,
:aie: Jacques t'es trop rapide t'es passé avant moi :mrgreen:
C'est pas grave je met le code que j'ai fait quand même :
Edit : j'ai pas évité le split :aie: mais maintenant je le saurais merci pour l'astuce Jacques :ccool:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 Sub StrCLong() Dim Txt$, T$, Ref, R, V, i& Txt = ":100:2:3241::452:60:": Txt = Application.Trim(Replace(Txt, ":", " ")) ReDim Ref(Len(Txt) - Len(Replace(Txt, " ", ""))) As Long R = Split(StrConv(Txt, vbUnicode), Chr(0)) For Each V In R If V > " " Then T = T & V Else Ref(i) = T: i = i + 1: T = "" End If Next End Sub
Je corrige mon code sans split, je devrais m'en souvenir après :scarymov: bien rentré dans le crâne :mrgreen:
:merci: JacquesCode:
1
2
3
4
5
6
7
8
9
10
11
12
13 Sub StrCLong2() Dim Txt$, T$, Ref, R() As Byte, S As Byte, V, i& Txt = ":100:2:3241::452:60:": Txt = Application.Trim(Replace(Txt, ":", " ")) ReDim Ref(Len(Txt) - Len(Replace(Txt, " ", ""))) As Long S = Asc(" "): R = StrConv(Txt & " ", vbFromUnicode) For Each V In R If V <> S Then T = T & Chr(V) Else Ref(i) = T: i = i + 1: T = "" End If Next End Sub
Edit 2 : la honte :oops:, dire que Marc en avait parlé et je l'ai utilisé dans un post (ok c'étais la 1ère fois que je l'utilisais), mais je l'ai fait;
par contre l'astuce de mettre le séparateur à la fin bien joué :plusser:
Bonjour tous,
je ne veux pas éterniser le post, mais dans le cas de très nombreux séparateur (qui pourraient compliquer la donne - après tous les chemins ou presque mène à Rome),
je vous propose 2 solutions (en VBA et en script Shell (Mac - la version PC étant à faire)) :
• VBA :
• Via le terminal (Shell - sur Mac 2011 et 2016) :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 Sub SansSepaDef() Dim Txt$, T$, Ref, R() As Byte, S As Byte, V, i& Txt = ":100;2?3241+-§452:60=" For i = 1 To Len(Txt) If Not IsNumeric(Mid(Txt, i, 1)) Then Mid(Txt, i, 1) = " " Next Txt = Application.Trim(Txt): i = 0 ReDim Ref(Len(Txt) - Len(Replace(Txt, " ", ""))) As Long S = Asc(" "): R = StrConv(Txt & " ", vbFromUnicode) For Each V In R If V <> S Then T = T & Chr(V) Else Ref(i) = T: i = i + 1: T = "" End If Next End Sub
Edit : Attention grande 1ère, Mon 1er Regex sou Excel PC => New Méthode pour le tableau long - aller je me mets :plusser: :mrgreen: - ceci dit, cela peut intéresser ;) :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 Sub SansSepaDef_Shell() Dim Txt$, T$, Ref, R() As Byte, S As Byte, V, i& Txt = ":100;2?3241+-§452:60=" Txt = MacScript("set nb to quoted form of " & Chr(34) & Txt & Chr(34) & Chr(13) & _ "do shell script ""NUMBER=$(echo "" & nb & "" | grep -oE '[0-9]+'); echo $NUMBER""") ' => résultat = "100 2 3241 452 60" ReDim Ref(Len(Txt) - Len(Replace(Txt, " ", ""))) As Long S = Asc(" "): R = StrConv(Txt & " ", vbFromUnicode) For Each V In R If V <> S Then T = T & Chr(V) Else Ref(i) = T: i = i + 1: T = "" End If Next End Sub
Apparemment , la version PC Regex est un chouia plus rapideCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 Sub RegexTBLong() Dim regex As Object, Txt$, VA, V, i As Byte Set regex = CreateObject("VBScript.RegExp") With regex .Pattern = "[0-9]+": .Global = True End With Txt = ":100:2:3241::452:60:": Set matches = regex.Execute(Txt) ReDim VA(1 To matches.Count) For Each V In matches i = i + 1: VA(i) = CLng(V) Next Set matches = Nothing End Sub