Pytanie Jak sprawdzić, czy ciąg "StartsWith" inny ciąg?


Jak napisałbym odpowiednik C # String.StartsWith w JavaScript?

var haystack = 'hello world';
var needle = 'he';

//haystack.startsWith(needle) == true

Uwaga: Jest to stare pytanie i jak wskazano w komentarzach ECMAScript 2015 (ES6) wprowadził .startsWith metoda. Jednak w chwili pisania tej aktualizacji (2015) obsługa przeglądarki jest daleki od ukończenia.


1547
2018-03-14 20:12


pochodzenie




Odpowiedzi:


Możesz użyć ECMAScript 6 String.prototype.startsWith() metoda, ale jest nie jest jeszcze obsługiwany we wszystkich przeglądarkach. Będziesz chciał użyć shim / polyfill, aby dodać go w przeglądarkach, które go nie obsługują. Tworzenie implementacji zgodnej z wszystkie szczegóły określone w specyfikacji jest nieco skomplikowany, a wersja zdefiniowana w tej odpowiedzi nie będzie działać; jeśli chcesz wiernego shim, użyj albo:

Po przejrzeniu metody (lub jeśli obsługujesz tylko przeglądarki i silniki JavaScript, które już ją mają), możesz użyć jej w ten sposób:

"Hello World!".startsWith("He"); // true

var haystack = "Hello world";
var prefix = 'orl';
haystack.startsWith(prefix); // false

1655
2018-03-14 20:19



JSPerf z natywnym startsWith: jsperf.com/js-startwith-prototype/8 - JimmyBoh
@ Gtournie, dlaczego zaczynałby być jedną z najgorszych metod testowania, czy łańcuch zaczyna się ciągiem? (zobacz swój komentarz tutaj: stackoverflow.com/questions/646628/...) jesteś bardziej entuzjastycznie nastawiony do porównywania postaci na postać. Mam nadzieję, że kompilatory są wystarczająco inteligentne, aby wygenerować ciąg znaków dla każdego ciągu znaków [indeks], ponieważ, jeśli po prostu napiszemy to: character = string [0] to przydzieli obiekt, nieskończenie MNIEJ wydajniejszy niż using startsWith (startsWith nie przydzieli żadnej pamięci ) - Martijn Scheffer
@MartijnScheffer: Odpowiedź była wielokrotnie edytowana, ponieważ odpowiedziałam i teraz jest zupełnie inna (usunąłem swój komentarz;). Zgadzam się, że starty ECMAScript 6 z użyciem metody to najlepszy sposób na zrobienie tego. - gtournie
@GrahamLaight, kiedy mówisz wspierany przez "IE", prawdopodobnie masz na myśli przez Edge. developer.mozilla.org/en/docs/Web/JavaScript/Reference/... - Marcus
@ Marcus, przepraszam, jeśli się myliłem - moje informacje pochodziły z: w3schools.com/jsref/jsref_startswith.asp - Graham Laight


Kolejna alternatywa z .lastIndexOf:

haystack.lastIndexOf(needle, 0) === 0

To wygląda wstecz haystack na wystąpienie needle począwszy od indeksu 0 z haystack. Innymi słowy, sprawdza tylko, czy haystack zaczynać z needle.

Zasadniczo powinno to mieć przewagę wydajności nad niektórymi innymi podejściami:

  • Nie przeszukuje całości haystack.
  • Nie tworzy nowego tymczasowego ciągu znaków, a następnie natychmiast go odrzuca.

1226
2018-01-02 16:14



Nie wiem, o co chodzi w przypadku @ rfcoder89 - jsfiddle.net/jkzjw3w2/1 - Gulfaraz Yasin
@ rfcoder89 Zwróć uwagę na drugi parametr lastIndexOf: "aba".lastIndexOf ("a") jest 2, jak wskazujesz, ale "aba".lastIndexOf ("a", 0) ma wartość 0, co jest poprawne - maxpolk
Dziękuję bardzo. String.startsWith nie działa z Androidem Lollipop WebView, ale ten fragment lastIndexOf działa !!! - Herman
z lastIndexOf ciąg jest przeszukiwany od końca do początku, więc przeszukuje cały ciąg: więc jego nieefektywność rośnie w poszukiwaniu bardzo długich łańcuchów. - willy wonka
@willywonka Nie, nie jest, jeśli masz 0 startIndex, jest wyszukiwany od 0 poz i jest to jedyny czek. Cały łańcuch jest przeszukiwany tylko wtedy, gdy fromIndex> = str.length. - greene


data.substring(0, input.length) === input

569
2018-03-14 20:14



@ANeves Podejrzewam, że to mocno zależy od przeglądarki i używanych danych. Zobacz odpowiedź Bena Weavera na aktualne pomiary. W aktualnie uruchomionej przeglądarce (pod Chrome 12.0.742 na Windows) podciągnie się pod względem powodzenia i przygotowuje wygrane regex do porażki. - cobbal
@ Cobbal Może. Ale .lastIndexOf(input, 0) porównuje pierwsze znaki N, podczas gdy .substring(0, input.length) === input liczy N, podciąga dane do długości N, a następnie porównuje te znaki N. O ile nie ma optymalizacji kodu, ta druga wersja nie może być szybsza od drugiej. Nie zrozumcie mnie źle, nigdy sam nie znajdę czegoś lepszego niż sugerowałeś. :) - ANeves
@Neves Ale .lastIndexOf na długim łańcuchu, który zwróci wartość false, przechodzi do iteracji po całym łańcuchu znaków (O (N)), natomiast przypadek .substring iteruje po potencjalnie znacznie mniejszym łańcuchu. Jeśli oczekujesz większości sukcesów lub tylko niewielkich nakładów, .lastIndexOf jest prawdopodobnie szybszy - w przeciwnym razie .ubsubstring jest prawdopodobnie szybszy. .substring ryzykuje również wyjątek, jeśli dane wejściowe są dłuższe niż sprawdzany ciąg. - Chris Moschini
@ ChrisMoschini, nie zapominaj, że rozwiązanie Mark Byers ma lastIndexOf zacznij od indeksu 0, a nie do końca. To też mnie potknęło. Mimo to sprawdzanie, z czym zaczyna się ciąg, jest tak powszechnym zadaniem, że JavaScript naprawdę powinien mieć odpowiedni interfejs API, a nie wszystkie idiomy i alternatywy, które widzisz na tej stronie, niezależnie od tego, jak inteligentne są. - Randall Cook
Wolę rozwiązanie cobbal od Mark's. Nawet jeśli znak jest szybszy i imponująca sztuczka używająca paramów, to jest bardzo trudna do odczytania w porównaniu do podłańcucha. - ThinkBonobo


Bez funkcji pomocnika, po prostu używając regex .test metoda:

/^He/.test('Hello world')

Aby to zrobić z ciągiem dynamicznym, a nie zakodowanym na stałe (zakładając, że ciąg nie będzie zawierał żadnych znaków sterujących wyrażeniem regularnym):

new RegExp('^' + needle).test(haystack)

Powinieneś sprawdzić Czy istnieje funkcja RegExp.escape w JavaScript? jeśli istnieje możliwość, że wyrażenie regularne pojawi się w ciągu znaków.


180
2018-01-04 00:59





Chciałem tylko dodać moją opinię na ten temat.

Myślę, że możemy po prostu użyć w ten sposób:

var haystack = 'hello world';
var needle = 'he';

if (haystack.indexOf(needle) == 0) {
  // Code if string starts with this substring
}

50
2018-02-12 14:47



Odpowiedź Mark Byersa została porównana dla wykonania trzech różnych prawidłowych podejść przez @relfor. To prawidłowe podejście nie było faworyzowane, ponieważ wymaga przeszukiwania całego ciągu znaków. - maxpolk
@maxpolk Myślę indexOf przestanie przeszukiwać cały łańcuch, gdy znajdzie pierwsze wystąpienie. Sprawdziłem to. - Mr.D
Jeśli pierwsze wystąpienie nie zostanie znalezione na samym początku, podejście to zaczyna rosnąć w sposób nieefektywny, im dłużej będzie go szukać, potencjalnie wyszukując, aż osiągnie koniec, zamiast poddawać się dużo wcześniej. Ponieważ istnieje potencjał nieefektywności, nie jest on preferowany wśród trzech prawidłowych podejść. - maxpolk
@ Mr.D A jeśli nie ma meczu? - momo
@momomo Następnie dodaj else kod. - Mr.D


Najlepsze rozwiązanie:

function startsWith(str, word) {
    return str.lastIndexOf(word, 0) === 0;
}

startsWith("aaa", "a")
true
startsWith("aaa", "ab")
false
startsWith("abc", "abc")
true
startsWith("abc", "c")
false
startsWith("abc", "a")
true
startsWith("abc", "ba")
false
startsWith("abc", "ab")
true

I oto jest endsWith jeśli ty też tego potrzebujesz:

function endsWith(str, word) {
    return str.indexOf(word, str.length - word.length) !== -1;
}

Dla tych, którzy wolą prototypować go w String: 

String.prototype.startsWith || (String.prototype.startsWith = function(word) {
    return this.lastIndexOf(word, 0) === 0;
});

String.prototype.endsWith   || (String.prototype.endsWith = function(word) {
    return this.indexOf(word, this.length - word.length) !== -1;
});

Stosowanie: 

"abc".startsWith("ab")
true
"c".ensdWith("c") 
true

42
2018-04-26 21:56



Myślę, że pomieszałeś lastIndexOf i indexOf w twoich funkcjach - startsWith powinien być return str.indexOf (word, 0) === 0; - Richard Matheson
@RichardMatheson problemem z użyciem indexOf jest to, że jeśli nie uda się dopasować na początku, będzie kontynuował przeszukiwanie całego łańcucha, przy czym lastIndexOf zaczyna się od długości słowa i wraca do zera. Rozumiem? - momo
Ahh tak teraz ma sens - nie zwracałem uwagi na indeksy, których używałeś. Bardzo fajna sztuczka! - Richard Matheson


Oto niewielka poprawa rozwiązania CMS:

if(!String.prototype.startsWith){
    String.prototype.startsWith = function (str) {
        return !this.indexOf(str);
    }
}

"Hello World!".startsWith("He"); // true

 var data = "Hello world";
 var input = 'He';
 data.startsWith(input); // true

Sprawdzanie, czy funkcja już istnieje, na wypadek gdyby przyszły przeglądarka wdrożyła ją w natywnym kodzie lub jeśli jest zaimplementowana przez inną bibliotekę. Na przykład biblioteka prototypów implementuje już tę funkcję.

Za pomocą ! jest nieco szybszy i bardziej zwięzły niż === 0 choć nie tak czytelny.


37
2018-05-27 02:54



Może to stanowić problem: jeśli wdrożona już implementacja zachowuje się inaczej niż moja własna, złamałoby to moją aplikację. - Christoph Wurm
Jest to omówione tutaj problem O (N) stackoverflow.com/questions/646628/javascript-startswith/... - Chris Moschini
za pomocą ! jest bardzo brudny - Jonny Leeds
-1; dodając to do String.prototype jest złym pomysłem, ponieważ nie zbliża się do niego spec dla String.prototype.startsWith. Każdy kod, który próbuje użyć metody ES6, może się nie powieść, jeśli to robisz; może również sprawdzić, czy metoda jest już zdefiniowana, zobaczyć, że jest (źle, przez ciebie) i nie dodawać zgodnego ze specyfikacją podkładki, prowadząc do nieprawidłowego zachowania w późniejszym czasie. - Mark Amery
To nie jest dobre. - momo


Sprawdź również underscore.string.js. Zawiera szereg przydatnych metod testowania i manipulowania strunami, w tym a startsWith metoda. Z dokumentów:

zaczynać z  _.startsWith(string, starts)

Ta metoda sprawdza, czy string zaczynać z starts.

_("image.gif").startsWith("image")
=> true

21
2018-05-31 18:29



potrzebowałem _.string.startsWith - Colonel Panic


Ostatnio zadałem sobie to samo pytanie.
Istnieje wiele możliwych rozwiązań, tutaj są 3 prawidłowe:

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0 (dodał po obejrzeniu filmu Marka Byersa odpowiedź)
  • za pomocą pętli:

    function startsWith(s,starter) {
      for (var i = 0,cur_c; i < starter.length; i++) {
        cur_c = starter[i];
        if (s[i] !== starter[i]) {
          return false;
        }
      }
      return true;
    }
    

Nie natknąłem się na ostatnie rozwiązanie, które powoduje użycie pętli.
Zaskakujące jest to, że to rozwiązanie przewyższa pierwsze 3 o znaczny margines.
Oto test jsperf, który wykonałem, aby dojść do tego wniosku: http://jsperf.com/startswith2/2

Pokój

ps: ecmascript 6 (harmonia) wprowadza natywną startsWith metoda dla ciągów.
Pomyśl tylko, ile czasu zostałoby zaoszczędzone, gdyby pomyśleli o włączeniu tak bardzo potrzebnej metody do samej początkowej wersji.

Aktualizacja

Jak zauważył Steve (pierwszy komentarz dotyczący tej odpowiedzi), powyższa funkcja niestandardowa wygeneruje błąd, jeśli zostanie podany prefiks jest krótszy niż cały ciąg. Naprawił to i dodał optymalizację pętli, którą można przeglądać http://jsperf.com/startswith2/4.

Zauważ, że istnieją dwie optymalizacje pętli, które zawiera Steve, pierwsze z nich wykazały lepszą wydajność, dlatego opublikuję poniższy kod:

function startsWith2(str, prefix) {
  if (str.length < prefix.length)
    return false;
  for (var i = prefix.length - 1; (i >= 0) && (str[i] === prefix[i]); --i)
    continue;
  return i < 0;
}

15
2018-05-17 09:07



Zobacz najnowszą wersję Oprócz błędu w powyższej wersji (będzie on rzucał, jeśli ciąg jest krótszy niż prefiks), jest również wolniejszy niż bardziej zoptymalizowana wersja. Widzieć jsperf.com/startswith2/4 i jsperf.com/js-startswith/35. - Steve Hollasch
^ Dziękujemy za wskazanie przypadku, w którym ciąg jest krótszy niż przedrostek - Raj Nathani
jsperf.com/startswith2/29 => startsWith5 jest zwięzły i działa naprawdę dobrze =) - gtournie


Ponieważ jest to tak popularne, uważam, że warto podkreślić, że w ECMA 6 zastosowano tę metodę, a do tego należy użyć "oficjalnej" polyfill, aby zapobiec przyszłym problemom i łzom.

Na szczęście eksperci z Mozilli zapewniają nam jeden:

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith

if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position) {
        position = position || 0;
        return this.indexOf(searchString, position) === position;
    };
}

Należy pamiętać, że ma to tę zaletę, że zostanie z gracją zignorowana przy przejściu na ECMA 6.


10
2018-01-05 11:34



Niewłaściwe, patrz stackoverflow.com/a/36876507/961018 - momo