Czy w javascript istnieje odpowiednik String.indexOf (), który przyjmuje wyrażenie regularne zamiast ciągu dla pierwszego pierwszego parametru, jednocześnie dopuszczając drugi parametr?
Muszę zrobić coś takiego
str.indexOf(/[abc]/ , i);
i
str.lastIndexOf(/[abc]/ , i);
Podczas gdy String.search () przyjmuje wyrażenie regularne jako parametr, nie pozwala mi podać drugiego argumentu!
Edycja:
Okazało się to trudniejsze niż początkowo myślałem, dlatego napisałem małą funkcję testową do przetestowania wszystkich dostarczonych rozwiązań ... zakłada, że do obiektu String zostały dodane regexIndexOf i regexLastIndexOf.
function test (str) {
var i = str.length +2;
while (i--) {
if (str.indexOf('a',i) != str.regexIndexOf(/a/,i))
alert (['failed regexIndexOf ' , str,i , str.indexOf('a',i) , str.regexIndexOf(/a/,i)]) ;
if (str.lastIndexOf('a',i) != str.regexLastIndexOf(/a/,i) )
alert (['failed regexLastIndexOf ' , str,i,str.lastIndexOf('a',i) , str.regexLastIndexOf(/a/,i)]) ;
}
}
i testuję w następujący sposób, aby upewnić się, że przynajmniej dla jednego wyrażenia regularnego wynik jest taki sam, jak gdybyśmy użyli indexOf
// Poszukaj a wśród
testu xes („xxx”);
test („axx”);
test („xax”);
test („xxa”);
test („axa”);
test („xaa”);
test („aax”);
test („aaa”);
źródło
|
wewnątrz[ ]
pasuje do dosłownego charakteru|
. Prawdopodobnie miałeś na myśli[abc]
.Odpowiedzi:
Łącząc kilka wspomnianych już podejść (indexOf jest oczywiście dość prosty), myślę, że są to funkcje, które wykonają tę sztuczkę:
Oczywiście modyfikacja wbudowanego obiektu String spowodowałaby wysłanie czerwonych flag dla większości ludzi, ale może to być jeden raz, gdy nie jest to aż tak wielka sprawa; po prostu bądź tego świadomy.
AKTUALIZACJA: Edytowana
regexLastIndexOf()
tak, aby wyglądałalastIndexOf()
teraz naśladować . Daj mi znać, jeśli nadal nie działa i pod jakimi warunkami.AKTUALIZACJA: Przechodzi wszystkie testy znalezione w komentarzach na tej stronie i moje. Oczywiście nie oznacza to, że jest kuloodporny. Wszelkie opinie są mile widziane.
źródło
regexLastIndexOf
tylko indeks ostatniego nie pokrywającego się dopasowania.regex.lastIndex = result.index + 1;
zamiastregex.lastIndex = ++nextStop;
. Mam nadzieję, że przejdzie do następnego meczu znacznie szybciej, nie tracąc żadnego wyniku.Instancje
String
konstruktora mają.search()
metodę, która akceptuje RegExp i zwraca indeks pierwszego dopasowania.Aby rozpocząć wyszukiwanie od określonej pozycji (fałszowanie drugiego parametru
.indexOf()
), możeszslice
wyłączyć pierwszei
znaki:Ale to otrzyma indeks w krótszym ciągu (po odcięciu pierwszej części), więc będziesz chciał dodać długość odciętej części (
i
) do zwróconego indeksu, jeśli tak nie było-1
. To da ci indeks w oryginalnym ciągu:źródło
function regexIndexOf(text, offset) { var initial = text.substr(offset).search(/re/); if(initial >= 0) { initial += offset; } return initial; }
Mam dla ciebie krótką wersję. To działa dobrze dla mnie!
A jeśli chcesz prototypową wersję:
EDYCJA : jeśli chcesz dodać obsługę fromIndex
Aby z niego skorzystać, tak proste:
źródło
startIndex
parametr jak zwykleindeoxOf
ilastIndexOf
zrobić.startIndex
(lubfromIndex
). Mam nadzieję, że to pomoże!lastIndexOfRegex
powinien również dodać wartośćfromIndex
do wyniku."aRomeo Romeo".indexOfRegex(new RegExp("\\bromeo", 'gi'));
Wynik wyniesie 1, gdy powinien wynosić 7, ponieważ indexOf po raz pierwszy wyszuka „romeo”, bez względu na to, czy jest na początku słowa, czy nie.Posługiwać się:
Zobacz dokumentację tutaj.
źródło
0
i została opublikowana ... siedem lat później.Na podstawie odpowiedzi BaileyP. Główną różnicą jest to, że metody te zwracają się,
-1
jeśli wzorca nie można dopasować.Edycja: Dzięki odpowiedzi Jasona Buntinga wpadłem na pomysł. Dlaczego nie zmodyfikować
.lastIndex
właściwości wyrażenia regularnego? Chociaż będzie to działać tylko w przypadku wzorców z flagą globalną (/g
).Edycja: Zaktualizowano, aby przekazać przypadki testowe.
źródło
Możesz użyć substr.
źródło
RexExp
instancje mają już właściwość lastIndex (jeśli są globalne), więc to, co robię, to kopiowanie wyrażenia regularnego, modyfikowanie go nieznacznie, aby pasowało do naszych celów, - umieszczanieexec
go na łańcuchu znaków i przeglądanielastIndex
. To nieuchronnie będzie szybsze niż zapętlanie łańcucha. (Masz wystarczająco dużo przykładów, jak umieścić to w prototypie łańcucha, prawda?)Możesz także prototypować funkcje na obiekcie RegExp:
Krótkie wyjaśnienie, w jaki sposób modyfikuję
RegExp
: PoindexOf
prostu muszę się upewnić, że globalna flaga jest ustawiona. DlalastIndexOf
używam negatywnego wybiegania w przyszłość, aby znaleźć ostatnie wystąpienie, chyba żeRegExp
było już zgodne na końcu ciągu.źródło
Nie działa natywnie, ale z pewnością możesz dodać tę funkcjonalność
Nie w pełni przetestowałem te metody, ale wydaje się, że do tej pory działały.
źródło
Po tym, jak wszystkie proponowane rozwiązania zawiodły w ten czy inny sposób (edytuj: niektóre zostały zaktualizowane, aby przejść testy po tym, jak to napisałem), znalazłem implementację Mozilli dla Array.indexOf i Array.lastIndexOf
Użyłem ich do wdrożenia mojej wersji String.prototype.regexIndexOf i String.prototype.regexLastIndexOf w następujący sposób:
Wydają się zdawać funkcje testowe, które podałem w pytaniu.
Oczywiście działają one tylko wtedy, gdy wyrażenie regularne pasuje do jednego znaku, ale to jest wystarczające dla mojego celu, ponieważ będę go używać do rzeczy takich jak ([abc], \ s, \ W, \ D)
Będę nadal monitorować to pytanie, na wypadek gdyby ktoś zapewnił lepszą / szybszą / czystszą / bardziej ogólną implementację, która działa na dowolnym wyrażeniu regularnym.
źródło
Potrzebowałem
regexIndexOf
funkcji również dla tablicy, więc sam ją zaprogramowałem. Wątpię jednak, czy jest zoptymalizowany, ale myślę, że powinien działać poprawnie.źródło
W niektórych prostych przypadkach możesz uprościć wyszukiwanie do tyłu za pomocą podziału.
Ma to kilka poważnych problemów:
Ale z drugiej strony jest to o wiele mniej kodu. W przypadku wyrażenia regularnego o stałej długości, które nie mogą się pokrywać (np. W
/\s\w/
celu znalezienia granic słów), jest to wystarczające.źródło
W przypadku danych z rzadkimi dopasowaniami użycie ciągu string.search jest najszybsze w przeglądarkach. Ponownie kroi ciąg po każdej iteracji, aby:
Zrobiłem to dla gęstych danych. Jest skomplikowany w porównaniu do metody wykonywania, ale w przypadku gęstych danych jest 2-10 razy szybszy niż każda inna metoda, którą wypróbowałem, i około 100 razy szybciej niż przyjęte rozwiązanie. Główne punkty to:
Nowe wyrażenie regularne jest wykonywane i zwracane są wyniki zarówno tego, jak i pierwszego exec;
jsPerf metod
Nie rozumiem celu testów do góry. Sytuacje wymagające wyrażenia regularnego są niemożliwe do porównania z wywołaniem indexOf, które moim zdaniem jest celem stworzenia metody w pierwszej kolejności. Aby pomyślnie przejść test, bardziej sensowne jest użycie „xxx + (?! x)” niż dostosowanie iteracji wyrażenia regularnego.
źródło
Ostatni indeks Jasona Buntinga nie działa. Mój nie jest optymalny, ale działa.
źródło
Nadal nie ma natywnych metod wykonujących żądane zadanie.
Oto kod, którego używam. Naśladuje on zachowanie metod String.prototype.indexOf i String.prototype.lastIndexOf , ale akceptuje także RegExp jako argument wyszukiwania oprócz łańcucha reprezentującego wartość do wyszukania.
Tak, odpowiedź jest dość długa, ponieważ stara się jak najlepiej przestrzegać aktualnych standardów i oczywiście zawiera rozsądną liczbę komentarzy JSDOC . Jednak po zminimalizowaniu kod ma tylko 2,27 KB, a po skompresowaniu do gzipa ma tylko 1023 bajtów.
Dwie metody, które to dodaje
String.prototype
(używając Object.defineProperty, jeśli są dostępne) to:searchOf
searchLastOf
Przeszedł wszystkie testy opublikowane przez PO, a dodatkowo dość dokładnie przetestowałem procedury w moim codziennym użyciu i starałem się mieć pewność, że działają one w wielu środowiskach, ale opinie i problemy są zawsze mile widziane.
źródło
Jeśli szukasz bardzo prostego wyszukiwania lastIndex za pomocą RegExp i nie obchodzi Cię, czy naśladuje lastIndexOf do ostatniego szczegółu, może to przykuć twoją uwagę.
Po prostu odwracam ciąg i odejmuję indeks pierwszego wystąpienia od długości - 1. Zdarza się, że mój test jest pozytywny, ale myślę, że może wystąpić problem z wydajnością przy długich ciągach.
źródło
Użyłem,
String.prototype.match(regex)
który zwraca tablicę ciągów wszystkich znalezionych dopasowań podanychregex
w ciągu (więcej informacji tutaj ):źródło
Użyj standardowych wyrażeń regularnych:
źródło
Cóż, ponieważ po prostu chcesz dopasować pozycję postaci , regex jest prawdopodobnie przesadny.
Zakładam, że wszystko czego chcesz to zamiast „znajdź pierwszą z tych postaci”, po prostu znajdź pierwszą z tych postaci.
Jest to oczywiście prosta odpowiedź, ale robi to, co postawiono w pytaniu, aczkolwiek bez części wyrażenia regularnego (ponieważ nie wyjaśniłeś, dlaczego konkretnie miało to być wyrażenie regularne)
źródło