Próbuję znaleźć pozycje wszystkich wystąpień ciągu w innym ciągu, bez uwzględniania wielkości liter.
Na przykład, biorąc pod uwagę ciąg:
Nauczyłem się grać na ukulele w Libanie.
i ciąg wyszukiwania le
, chcę uzyskać tablicę:
[2, 25, 27, 33]
Oba łańcuchy będą zmiennymi - tj. Nie mogę zakodować ich wartości na stałe.
Pomyślałem, że to łatwe zadanie w przypadku wyrażeń regularnych, ale po dłuższej walce ze znalezieniem takiego, który zadziała, nie miałem szczęścia.
Znalazłem przykład, jak to zrobić .indexOf()
, ale z pewnością musi być bardziej zwięzły sposób, aby to zrobić?
źródło
le
tutaj ciąg zmiennych? Nawet podczas korzystanianew Regexp(str);
z niebezpieczeństwa znaków specjalnych czai się$2.50
na przykład szukając . Coś takiegoregex = new Regexp(dynamicstring.replace(/([\\.+*?\\[^\\]$(){}=!<>|:])/g, '\\$1'));
byłoby bliższe IMHO. Nie jestem pewien, czy js ma wbudowany mechanizm ucieczki wyrażeń regularnych.new RegExp(searchStr)
byłoby sposobem, i tak, w ogólnym przypadku musiałbyś uciec od znaków specjalnych. Nie warto tego robić, chyba że potrzebujesz tego poziomu ogólności.searchStr=aaa
i tostr=aaaaaa
. Wtedy zamiast znaleźć 4 wystąpienia, twój kod znajdzie tylko 2, ponieważ wykonujesz pomijaniesearchStr.length
w pętli.Oto darmowa wersja regex:
EDYTUJ : a jeśli chcesz dopasować ciągi, takie jak „aaaa” i „aa”, aby znaleźć [0, 2], użyj tej wersji:
źródło
var result = indexes('aaaa', 'aa')
? Oczekiwany wynik powinien być[0, 1, 2]
lub[0, 2]
?i+=find.length;
i w innymi++
Na pewno możesz to zrobić!
Edycja: naucz się pisać RegExp
Zrozumiałem też, że to nie jest dokładnie to, czego chcesz, ponieważ
lastIndex
mówi nam, że koniec igły nie jest początkiem, ale jest blisko - możesz wcisnąćre.lastIndex-needle.length
do tablicy wyników ...Edycja: dodawanie linku
Odpowiedź @Tim Down wykorzystuje obiekt wyników z RegExp.exec (), a wszystkie moje zasoby JavaScript prześlizgują się nad jego użyciem (poza podaniem dopasowanego ciągu). Więc kiedy używa
result.index
, jest to jakiś nienazwany obiekt dopasowania. W opisie exec w MDC , faktycznie opisują ten obiekt z przyzwoitymi szczegółami.źródło
Jedna wkładka przy użyciu
String.protype.matchAll
(ES2020):Używając swoich wartości:
Jeśli martwisz się o zrobienie spreadu i a
map()
w jednej linii, uruchomiłem go zfor...of
pętlą na milion iteracji (używając twoich ciągów znaków). Jedna liner zajmuje średnio 1420 ms, podczas gdy średniafor...of
wynosi 1150 ms na moim komputerze. Nie jest to nieznacząca różnica, ale jedna wkładka będzie działać dobrze, jeśli wykonujesz tylko kilka meczów.Zobacz
matchAll
na caniuseźródło
Jeśli chcesz tylko znaleźć pozycję wszystkich dopasowań, chciałbym wskazać ci mały hack:
Może nie nadawać się do zastosowania, jeśli masz wyrażenie RegExp o zmiennej długości, ale dla niektórych może być pomocne.
Rozróżniana jest wielkość liter. W przypadku niewrażliwości na wielkość liter użyj
String.toLowerCase
wcześniej funkcji.źródło
Oto prosty kod
źródło
Postępuj zgodnie z odpowiedzią @jcubic, jego rozwiązanie spowodowało małe zamieszanie w mojej sprawie
Na przykład
var result = indexes('aaaa', 'aa')
zwróci[0, 1, 2]
zamiast tego[0, 2]
Więc zaktualizowałem nieco jego rozwiązanie jak poniżej, aby pasowało do mojej sprawy
źródło
Dzięki za wszystkie odpowiedzi. Przejrzałem je wszystkie i wymyśliłem funkcję, która daje pierwszemu i ostatniemu indeksowi każdego wystąpienia podciągu „igłowego”. Wrzucam to tutaj na wypadek, gdyby to komuś pomogło.
Należy pamiętać, że to nie to samo, co pierwotne żądanie dotyczące tylko początku każdego wystąpienia. Bardziej pasuje do mojego przypadku, ponieważ nie musisz utrzymywać długości igły.
źródło
Sprawdź to rozwiązanie, które będzie w stanie znaleźć ten sam ciąg znaków, daj mi znać, jeśli czegoś brakuje lub nie jest dobrze.
źródło
źródło
poniższy kod wykona zadanie za Ciebie:
źródło
Użyj String.prototype.match .
Oto przykład z samej dokumentacji MDN:
źródło