Mam arkusz programu Excel składający się z dwóch kolumn, z których jedna jest wypełniona ciągami, a druga jest pusta. Chciałbym użyć VBA do przypisania wartości komórek w pustej kolumnie na podstawie wartości sąsiedniego ciągu w drugiej kolumnie.
Dim regexAdmin As Object Set regexAdmin = CreateObject("VBScript.RegExp") regexAdmin.IgnoreCase = True regexAdmin.Pattern = "Admin" Dim i As Integer For i = 1 To 10 "let"s say there is 10 rows Dim j As Integer For j = 1 To 2 If regexAdmin.test(Cells(i, j).Value) Then Cells(i, j + 1).Value = "Exploitation" End If Next j Next i
Problem polega na tym, że gdy używasz tej pętli dla dużej ilości danych, jej działanie zajmuje zbyt dużo czasu i przez większość czasu po prostu powoduje awarię programu Excel.
Czy ktoś zna lepszy sposób na zrobienie tego?
Odpowiedź
Krótka odpowiedź brzmi:
Nie używaj vba , użyj formuły. W szczególności kombinacja IF
i SEARCH .
=IF(SEARCH($A1,"Admin")>0,"Exploitation","")
Ale to jest przegląd kodu, więc zróbmy to mimo wszystko.
-
Regex działa wolno. Wygląda na to, że „używasz go tylko do niewrażliwości na wielkość liter. Biorąc to pod uwagę, możesz bezpośrednio porównać wartości komórek, używając opcji
StrComp
z opcjąvbTextCompare
. ( przydatny artykuł na StrComp ) -
i
ij
są zwykle używane do liczników pętli, alerow
icol
mam więcej sensu w tym przypadku.
Oto, jak to mogłoby wyglądać:
Dim row As Integer For row = 1 To 10 "let"s say there is 10 rows Dim col As Integer For col = 1 To 2 If StrComp("Admin",Cells(row, col).Value,vbTextCompare) Then Cells(row, col + 1).Value = "Exploitation" End If Next col Next row
Odpowiedź
Myślę, że proste porównanie ciągów byłoby znacznie szybsze niż Regex.
Dim pattern as string pattern = "Admin" Dim i As Integer For i = 1 To 10 "let"s say there is 10 rows Dim j As Integer For j = 1 To 2 If Cells(i, j) = pattern Then Cells(i, j + 1) = "Exploitation" End If Next j Next i
Komentarze
- Ten kod nie ' odnosi się do porównania bez uwzględniania wielkości liter, ale ' jest poprawny. Wyrażenie regularne jest przesadą i w tym przypadku preferowane jest porównanie ciągów. (Swoją drogą, witamy w przeglądzie kodu!)
Odpowiedź
Czy mogę zasugerować 50% skrócenie czasu działania /wysiłek?
Dim row As Integer For row = 1 To 10 "let"s say there is 10 rows If StrComp("Admin",Cells(row, 1).Value,vbTextCompare) Then Cells(row, 2).Value = "Exploitation" End If Next row
Czy nikt nie zauważył, że OP mówi o „sprawdzaniu JEDNEJ kolumny, pisaniu do następnej sąsiedniej”, naprawdę? Po co więc zapętlić kolumny? Drugi przebieg sprawdziłby tylko pustą komórkę lub komórkę z „Wykorzystaniem”.
Odpowiedź
Wow. Po przeczytaniu pierwszych kilku wierszy zacząłem się zastanawiać:
- Dlaczego późne wiązanie?
- Po co w ogóle używać wyrażenia regularnego?
@ ckuhn203 odniósł się już do nazewnictwa w swojej odpowiedzi, ale znalazłem to:
Dim i As Integer For i = 1 To 10 "let"s say there is 10 rows
Przekształcone w to:
Dim row As Integer For row = 1 To 10 "let"s say there is 10 rows
… Nie potrzebuje już komentarza.
Chciałbym użyć VBA do przypisania wartości komórek w pustej kolumnie na podstawie wartości sąsiedniego ciągu w drugiej kolumnie.
Myślę, że „s [mis | ab] używając VBA: sam Excel bardzo dobrze radzi sobie z przypisywaniem wartości komórek na podstawie innych komórek ”.
regexAdmin.Pattern = "Admin"
Myślę, że „s [mis | ab] używając wyrażenia regularnego: jeśli twój wzór jest zwykłym słowem,” najprawdopodobniej próbujesz zabić komara bazooką. Niewłaściwe narzędzie dla t tutaj.
Odpowiedź
Zawsze, gdy uzyskujesz dostęp do obiektu Range, należy to zrobić za pomocą jednej operacji odczytu / zapisu.
Przed wejściem do pętli for powinieneś przeczytać cały zakres, z którym chcesz pracować.
data = Range(Cells(1,1), Cells(10,2)).Value
Teraz możesz pracować z danymi:
For i = 1 To 10 "let"s say there is 10 rows Dim j As Integer For j = 1 To 2 If regexAdmin.test(data(i, j)) Then data(i, j + 1) = "Exploitation" End If Next j Next i
Na koniec zapisz dane z powrotem do programu Excel:
Range(Cells(1,1), Cells(10,2)).Value = data
Odpowiedź
W B1:
=if(upper(A1)="ADMIN","Exploitation","")
Następnie po prostu wypełnij. To jest niewrażliwe na wielkość liter.
To automatyczne wypełnianie można wykonać na dwa sposoby, interaktywnie w arkuszu lub programowo:
Interaktywnie : Excel ma funkcję autouzupełniania. Po zaznaczeniu B1 i wstawieniu tej formuły wystarczy dwukrotnie kliknąć uchwyt wypełniania, który jest małym kwadratem w prawym dolnym rogu komórki, gdy jest on zaznaczony. Program Excel w inteligentny sposób skopiuje formułę na koniec ciągłego zakresu, który ma Oznacza to, że jeśli A1-A256 ma dane bez spacji, wypełni się automatycznie do B256. Alternatywnie, jeśli są spacje, przewiń w dół i wybierz B256 (lub jakikolwiek inny koniec). Następnie Ctrl + Shift + strzałka w górę, aby wybrać zakres prowadzący do B1 i Ctrl + D, aby go skopiować (pomyśl d = ditto)
Korzystanie z VBA … jeśli musisz to zrobić programowo: z formułą zawierającą komórkę jako wybór:
Selection.AutoFill Destination:=Range("B1:B19")
Dostępne są inne opcje autouzupełniania, które pozwalają wykonać kilka fajnych sztuczek.Może skopiować wartość literału zamiast formuły lub wypełnić serię na podstawie wzorca. Możesz również ustawić niestandardowe wzorce, które będzie rozpoznawać, na przykład linie biznesowe, które często powtarzasz w rzeczach lub miastach, w których masz sklepy itp.
Komentarze
- Rzeczywiście, witamy w Code Review! Całkowicie przegapiłem, że OP nie ' nie musiał przeszukiwać kolumny! ++ Najlepsze rozwiązanie tutaj.
Odpowiedź
Połączenie wszystkich pozostałych odpowiedzi sprawiło, że wielkość liter nie była rozróżniana, jak regex w oryginale, usunięto potrzebę określenia liczby wierszy i deklarowania wszystkich zmiennych, ponieważ Option Explicit
pozwala uniknąć tak wielu błędów w vba
Option Explicit Sub checkForExploit() Dim row As Integer Dim data() As Variant Dim datarange As Range Set datarange = Range("A1:B10") data = datarange.Value For row = 1 To UBound(data, 1) If LCase(data(row, 1)) = "admin" Then data(row, 2) = "Exploitation" End If Next row datarange.Value = data End Sub