Jak sprawdzić, czy ciąg „StartsWith” inny ciąg?


Odpowiedzi:


1773

Możesz użyć String.prototype.startsWith()metody ECMAScript 6 , ale nie jest ona jeszcze obsługiwana we wszystkich przeglądarkach . Będziesz chciał użyć podkładki / wypełnienia, aby dodać ją w przeglądarkach, które jej nie obsługują. Tworzenie implementacji zgodnej ze wszystkimi szczegółami określonymi w specyfikacji jest trochę skomplikowane. Jeśli chcesz wiernego podkładki, użyj jednego z poniższych:

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

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

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

@gtournie dlaczego miałby być. Czy byłaby to jedna z najgorszych metod sprawdzania, czy łańcuch zaczyna się od łańcucha? (zobacz swój komentarz tutaj: stackoverflow.com/questions/646628/... ) bardziej entuzjastycznie porównujesz postać do postaci. Mam nadzieję, że kompilatory są wystarczająco inteligentne, aby NIE generować łańcucha dla każdego łańcucha [indeks], ponieważ jeśli po prostu napiszesz: znak = łańcuch [0] przydzieli obiekt, nieskończenie MNIEJSZY efektywny niż przy użyciu StartWith (StartWith nie przydzieli żadnej pamięci )
Martijn Scheffer

@MartijnScheffer: Odpowiedź była edytowana wiele razy, odkąd odpowiedziałem i jest teraz zupełnie inna (usunąłem swój komentarz;). Zgadzam się, że metoda ECMAScript 6 zaczyna się od metody jest najlepszym sposobem na to.
gtournie

6
@GrahamLaight, kiedy mówisz, że jest wspierany przez „IE”, prawdopodobnie masz na myśli Edge. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Marcus

@Marcus, przepraszam, jeśli się myliłem - moje informacje pochodzą z: w3schools.com/jsref/jsref_startswith.asp
Graham Laight

OSTRZEŻENIE! Te testy jsperf nie działają w przeglądarkach, które są dobre w kompilacji JIT. Przeglądarki takie jak Firefox i Chrome czasami rozpoznają go po odrzuceniu wyniku operacji i dlatego nie wykonują operacji . Poza tym nowoczesne silniki javascript używają przewidywania gałęzi , więc łańcuchy testowe powinny być różne w każdej iteracji.
Aloso

1282

Inna alternatywa z .lastIndexOf:

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

To wygląda do tyłu haystacko wystąpieniu needlepocząwszy od wskaźnika 0z haystack. Innymi słowy, sprawdza tylko, czy haystackzaczyna się od needle.

Zasadniczo powinno to mieć przewagę wydajności w stosunku do niektórych innych podejść:

  • Nie przeszukuje całości haystack.
  • Nie tworzy nowego łańcucha tymczasowego, a następnie natychmiast go odrzuca.

1
Nie jestem pewien, który przypadek zajmuje się @ rfcoder89 - jsfiddle.net/jkzjw3w2/1
Gulfaraz Rahman

5
@ rfcoder89 Zwróć uwagę, że drugi parametr lastIndexOf: "aba".lastIndexOf ("a")ma 2, jak "aba".lastIndexOf ("a", 0)
zauważyłeś

1
Dziękuję bardzo. String.startsWith nie działa na Androidzie Lollipop dla systemu Android, ale ten fragment kodu LastIndexOf działa !!!
Herman,

with lastIndexOf ciąg jest przeszukiwany od końca do początku, więc przeszukuje cały ciąg: więc jego nieefektywność rośnie dla bardzo długich ciągów do przeszukiwania.
willy wonka

8
@willywonka Nie, to nie jest, jeśli masz 0 startIndex, jest przeszukiwany od 0 pozycji i jest to jedyny czek. Cały ciąg jest przeszukiwany tylko wtedy, gdy fromIndex> = str.length.
greene

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

3
@ANeves Podejrzewam, że silnie zależy od przeglądarki i użytych danych. Zobacz odpowiedź Bena Weavera na rzeczywiste pomiary. W przeglądarce, na której aktualnie pracuję (Chrome 12.0.742 w systemie Windows), podciąg wygrywa dla sukcesu, a przygotowane wyrażenia regularne wygrywają dla niepowodzenia.
cobbal

4
@cobbal Może. Ale .lastIndexOf(input, 0)porównuje pierwsze N ​​znaków, podczas gdy .substring(0, input.length) === inputliczy N, podciąga dane do długości N, a następnie porównuje te N znaków. O ile nie ma optymalizacji kodu, ta druga wersja nie może być szybsza od drugiej. Nie zrozumcie mnie źle, nigdy bym nie znalazł czegoś lepszego niż sugerowałeś. :)
ANeves

2
@ANeves Ale .lastIndexOf na długim łańcuchu, który zwróci false, będzie iterował cały łańcuch (O (N)), podczas gdy .substring iteruje na 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 .substring jest prawdopodobnie szybszy. .substring ryzykuje również wyjątek, jeśli dane wejściowe są dłuższe niż sprawdzany ciąg.
Chris Moschini

14
@ChrisMoschini, nie zapominaj, że rozwiązanie Marka Byersa lastIndexOfzaczęło się od indeksu 0, a nie do końca. Na początku mnie też to potknęło. Mimo to sprawdzanie, od czego zaczyna się ciąg, jest tak częstym zadaniem, że JavaScript naprawdę powinien mieć do tego odpowiedni interfejs API, a nie wszystkie idiomy i alternatywy, które widzisz na tej stronie, choć są one sprytne.
Randall Cook

4
Wolę rozwiązanie Cobbala niż Marka. Nawet jeśli znak jest szybszy i imponująca sztuczka przy użyciu parametrów, bardzo trudno jest go odczytać w porównaniu do podłańcucha.
ThinkBonobo,

183

Bez funkcji pomocniczej, wystarczy użyć .testmetody regex :

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

Aby to zrobić za pomocą ciągu dynamicznego zamiast zakodowanego na stałe (zakładając, że ciąg nie będzie zawierał żadnych znaków kontrolnych wyrażenia regularnego):

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

Powinieneś sprawdzić Czy w JavaScript jest funkcja RegExp.escape? jeśli istnieje możliwość pojawienia się w ciągu znaków kontrolnych wyrażenia regularnego.


1
Aby użyć wyrażenia rozróżniającego /^he/i
wielkość liter

64

Najlepsze rozwiązanie:

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

A oto koniec: jeśli tego też 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

Z metodą:

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

Myślę, że pomieszałeś lastIndexOf i indexOf w swoich funkcjach - startWith powinien być zwrócony str.indexOf (słowo, 0) === 0;
Richard Matheson

5
@RichardMatheson problem z użyciem indexOf polega na tym, że jeśli nie uda się dopasować na początku, będzie kontynuował wyszukiwanie całego łańcucha, przy czym lastIndexOf zaczyna się od długości słowa i wraca do zera. Rozumiem?
mmm

2
Ach, tak, ma to teraz sens - nie zwracałem uwagi na wskaźniki, których używałeś. Bardzo fajna sztuczka!
Richard Matheson

54

Chciałem tylko dodać swoją 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
}

2
Odpowiedź Marka Byersa została porównana pod kątem wydajności trzech różnych poprawnych podejść @relfor. To poprawne podejście nie zostało uprzywilejowane, ponieważ wymaga przeszukania całego łańcucha.
maxpolk

@maxpolk Myślę, że indexOfprzestanie przeszukiwać cały ciąg, gdy znajdzie pierwsze wystąpienie. Sprawdziłem to.
Mr.D

8
Jeśli pierwsze wystąpienie nie zostanie znalezione na samym początku, podejście to staje się nieefektywne, im dłużej będzie go szukało, potencjalnie szukając aż do samego końca, zamiast poddawać się znacznie wcześniej. Ponieważ istnieje potencjał nieefektywności, nie jest on preferowany wśród trzech poprawnych podejść.
maxpolk

2
@ Mr.D A jeśli nie ma dopasowania?
mmm

w przeciwnym razie po przeszukaniu całego stogu siana? jest lepsze: stackoverflow.com/a/36876507/961018 .. wyszukuje tylko do długości słowa
mmm

39

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ła przeglądarka zaimplementowała ją w kodzie natywnym lub jeśli została zaimplementowana przez inną bibliotekę. Na przykład biblioteka prototypów już implementuje tę funkcję.

Korzystanie !jest nieco szybsze i bardziej zwięzłe niż === 0nie tak czytelne.


1
Może to stać się problemem: jeśli wdrożona już implementacja zachowuje się inaczej niż moja, spowoduje to uszkodzenie mojej aplikacji.
Christoph Wurm,

2
To dotyczy problemu O (N) omówionego tutaj stackoverflow.com/questions/646628/javascript-startswith/…
Chris Moschini

1
za pomocą ! jest bardzo niechlujny
JonnyRaa

-1; dodając do tego String.prototypejest to zły pomysł, ponieważ nie są nigdzie blisko zgodne ze specyfikacją dla String.prototype.startsWith. Każdy kod, który próbuje użyć metody ES6, może zawieść, jeśli to zrobisz; może wyglądać, czy metoda jest już zdefiniowana, czy jest (źle przez ciebie) i nie dodawać podkładki zgodnej ze specyfikacją, co później prowadzi do nieprawidłowego zachowania.
Mark Amery

21

Sprawdź także underscore.string.js . Zawiera wiele użytecznych metod testowania i manipulacji ciągami, w tym startsWithmetodę. Z dokumentów:

zaczynać z _.startsWith(string, starts)

Ta metoda sprawdza, czy stringzaczyna się od starts.

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

1
Potrzebowałem_.string.startsWith
pułkownik Panic

15

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 znak Byers męska 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 spotkałem ostatniego rozwiązania, które wykorzystuje pętlę.
Nieoczekiwanie to rozwiązanie przewyższa pierwsze 3 o znaczny margines.
Oto test jsperf, który przeprowadziłem, aby dojść do tego wniosku: http://jsperf.com/startswith2/2

Pokój

ps: ecmascript 6 (harmonia) wprowadza natywną startsWithmetodę ciągów.
Pomyśl tylko, ile czasu by by zaoszczędzono, gdyby pomyśleli o włączeniu tej bardzo potrzebnej metody do samej początkowej wersji.

Aktualizacja

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

Zauważ, że istnieją 2 optymalizacje pętli, które zawiera Steve, pierwsza z nich wykazała lepszą wydajność, dlatego opublikuję ten kod poniżej:

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;
}

Zobacz najnowszą wersję Oprócz błędu w powyższej wersji (wyrzuci, jeśli łańcuch jest krótszy niż przedrostek), jest również wolniejszy niż wersja bardziej zoptymalizowana. Zobacz jsperf.com/startswith2/4 i jsperf.com/js-startswith/35 .
Steve Hollasch

^ Dziękujemy za wskazanie przypadku, w którym łańcuch jest krótszy niż przedrostek
Raj Nathani

jsperf.com/startswith2/29 => startWith5 jest zwięzły i działa naprawdę dobrze =)
gtournie,

11

Ponieważ jest to tak popularne, myślę, że warto zauważyć, że istnieje implementacja tej metody w ECMA 6 i przygotowując się do tego, należy użyć „oficjalnej” polifill, aby zapobiec przyszłym problemom i łzom.

Na szczęście eksperci 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 zostaje wdzięcznie zignorowane po przejściu na ECMA 6.


5

Najlepszym rozwiązaniem jest zaprzestanie używania wywołań bibliotecznych i po prostu rozpoznanie, że pracujesz z dwiema tablicami. Ręcznie wdrożona implementacja jest zarówno krótka, jak i szybsza niż każde inne rozwiązanie, jakie tu widziałem.

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;
}

Dla porównania wydajności (sukces i porażka) zobacz http://jsperf.com/startswith2/4 . (Upewnij się, że sprawdziłeś późniejsze wersje, które mogły być atutem mojej).


2

Właśnie dowiedziałem się o tej bibliotece ciągów:

http://stringjs.com/

Dołącz plik js, a następnie użyj Szmiennej w następujący sposób:

S('hi there').endsWith('hi there')

Można go również użyć w NodeJS, instalując go:

npm install string

Wymagając go jako Szmiennej:

var S = require('string');

Strona internetowa zawiera również linki do alternatywnych bibliotek ciągów, jeśli ta nie przypadnie Ci do gustu.


2
  1. Pytanie jest nieco stare, ale chciałem napisać tę odpowiedź, aby pokazać kilka testów porównawczych, które wykonałem na podstawie wszystkich podanych tutaj odpowiedzi i jsperf udostępnionego przez Jima Bucka.

Zasadniczo potrzebowałem szybkiego sposobu na sprawdzenie, czy długa igła znajduje się w długim stogu siana i czy są bardzo podobne, z wyjątkiem ostatnich postaci.

Oto kod, który napisałem, który dla każdej funkcji (splice, podłańcuch, startWith itp.) Testuje zarówno, gdy zwracają wartość false i true względem ciągu stogu siana ( nestedString) o wartości 1.000.0001 znaków oraz ciągu fałszywej lub prawdziwej igły 1.000.000 znaki ( testParentStringFalsei testParentStringTrueodpowiednio):

// nestedString is made of 1.000.001 '1' repeated characters.
var nestedString = '...'

// testParentStringFalse is made of 1.000.000 characters,
// all characters are repeated '1', but the last one is '2',
// so for this string the test should return false.
var testParentStringFalse = '...'

// testParentStringTrue is made of 1.000.000 '1' repeated characters,
// so for this string the test should return true.
var testParentStringTrue = '...'

// You can make these very long strings by running the following bash command
// and edit each one as needed in your editor
// (NOTE: on OS X, `pbcopy` copies the string to the clipboard buffer,
//        on Linux, you would probably need to replace it with `xclip`):
// 
//     printf '1%.0s' {1..1000000} | pbcopy
// 

function testString() {
    let dateStart
    let dateEnd
    let avg
    let count = 100000
    const falseResults = []
    const trueResults = []

    /* slice */
    console.log('========> slice')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.slice(0, testParentStringFalse.length) === testParentStringFalse
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'slice',
        avg
    }
    console.log(`testString() slice = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.slice(0, testParentStringTrue.length) === testParentStringTrue
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'slice',
        avg
    }
    console.log(`testString() slice = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== slice')
    console.log('')
    /* slice END */

    /* lastIndexOf */
    console.log('========> lastIndexOf')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.lastIndexOf(testParentStringFalse, 0) === 0
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'lastIndexOf',
        avg
    }
    console.log(`testString() lastIndexOf = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.lastIndexOf(testParentStringTrue, 0) === 0
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'lastIndexOf',
        avg
    }
    console.log(`testString() lastIndexOf = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== lastIndexOf')
    console.log('')
    /* lastIndexOf END */

    /* indexOf */
    console.log('========> indexOf')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.indexOf(testParentStringFalse) === 0
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'indexOf',
        avg
    }
    console.log(`testString() indexOf = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.indexOf(testParentStringTrue) === 0
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'indexOf',
        avg
    }
    console.log(`testString() indexOf = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== indexOf')
    console.log('')
    /* indexOf END */

    /* substring */
    console.log('========> substring')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.substring(0, testParentStringFalse.length) === testParentStringFalse
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'substring',
        avg
    }
    console.log(`testString() substring = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.substring(0, testParentStringTrue.length) === testParentStringTrue
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'substring',
        avg
    }
    console.log(`testString() substring = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== substring')
    console.log('')
    /* substring END */

    /* startsWith */
    console.log('========> startsWith')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.startsWith(testParentStringFalse)
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'startsWith',
        avg
    }
    console.log(`testString() startsWith = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.startsWith(testParentStringTrue)
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'startsWith',
        avg
    }
    console.log(`testString() startsWith = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== startsWith')
    console.log('')
    /* startsWith END */

    falseResults.sort((a, b) => a.avg - b.avg)
    trueResults.sort((a, b) => a.avg - b.avg)

    console.log('false results from fastest to slowest avg:', falseResults)
    console.log('true results from fastest to slowest avg:', trueResults)
}

Ten test porównawczy przeprowadziłem w Chrome 75 , Firefox 67 , Safari 12 i Opera 62 .

Nie zawarłem Edge i IE, ponieważ nie mam ich na tym komputerze, ale jeśli ktoś z was chce uruchomić skrypt przeciwko Edge i przynajmniej IE 9 i udostępnić wyniki tutaj, byłbym bardzo ciekawy, aby zobaczyć wyniki.

Pamiętaj tylko, że musisz odtworzyć 3 długie łańcuchy i zapisać skrypt w pliku, który następnie otworzysz w przeglądarce, ponieważ kopiowanie / wklejanie w konsoli przeglądarki zablokuje go, ponieważ długość każdego łańcucha wynosi> = 1.000.000).

Oto wyniki:

Chrome 75 ( substringwygrywa):

false results from fastest to slowest avg:
1)  {"label":"substring","avg":0.08271}
2)  {"label":"slice","avg":0.08615}
3)  {"label":"lastIndexOf","avg":0.77025}
4)  {"label":"indexOf","avg":1.64375}
5)  {"label":"startsWith","avg":3.5454}

true results from fastest to slowest avg:
1)  {"label":"substring","avg":0.08213}
2)  {"label":"slice","avg":0.08342}
3)  {"label":"lastIndexOf","avg":0.7831}
4)  {"label":"indexOf","avg":0.88988}
5)  {"label":"startsWith","avg":3.55448}

Firefox 67 ( indexOfwygrywa):

false results from fastest to slowest avg
1)  {"label":"indexOf","avg":0.1807}
2)  {"label":"startsWith","avg":0.74621}
3)  {"label":"substring","avg":0.74898}
4)  {"label":"slice","avg":0.78584}
5)  {"label":"lastIndexOf","avg":0.79668}

true results from fastest to slowest avg:
1)  {"label":"indexOf","avg":0.09528}
2)  {"label":"substring","avg":0.75468}
3)  {"label":"startsWith","avg":0.76717}
4)  {"label":"slice","avg":0.77222}
5)  {"label":"lastIndexOf","avg":0.80527}

Safari 12 ( slicewygrywa dla fałszywych wyników, startsWithwygrywa dla prawdziwych wyników, również Safari jest najszybszym pod względem całkowitego czasu na wykonanie całego testu):

false results from fastest to slowest avg:
1) "{\"label\":\"slice\",\"avg\":0.0362}"
2) "{\"label\":\"startsWith\",\"avg\":0.1141}"
3) "{\"label\":\"lastIndexOf\",\"avg\":0.11512}"
4) "{\"label\":\"substring\",\"avg\":0.14751}"
5) "{\"label\":\"indexOf\",\"avg\":0.23109}"

true results from fastest to slowest avg:
1) "{\"label\":\"startsWith\",\"avg\":0.11207}"
2) "{\"label\":\"lastIndexOf\",\"avg\":0.12196}"
3) "{\"label\":\"substring\",\"avg\":0.12495}"
4) "{\"label\":\"indexOf\",\"avg\":0.33667}"
5) "{\"label\":\"slice\",\"avg\":0.49923}"

Opera 62 ( substringwygrywa. Wyniki są podobne do Chrome i nie jestem zaskoczony, ponieważ Opera oparta jest na Chromium i Blink):

false results from fastest to slowest avg:
{"label":"substring","avg":0.09321}
{"label":"slice","avg":0.09463}
{"label":"lastIndexOf","avg":0.95347}
{"label":"indexOf","avg":1.6337}
{"label":"startsWith","avg":3.61454}

true results from fastest to slowest avg:
1)  {"label":"substring","avg":0.08855}
2)  {"label":"slice","avg":0.12227}
3)  {"label":"indexOf","avg":0.79914}
4)  {"label":"lastIndexOf","avg":1.05086}
5)  {"label":"startsWith","avg":3.70808}

Okazuje się, że każda przeglądarka ma własne szczegóły implementacji (oprócz Opery, która jest oparta na Chromium i Blink Chrome).

Oczywiście można i należy wykonać dalsze testy z różnymi przypadkami użycia (np. Gdy igła jest naprawdę krótka w porównaniu do stogu siana, gdy stóg siana jest krótszy niż igła itp.), Ale w moim przypadku musiałem porównać bardzo długie struny i chciałem się tym tutaj podzielić.


1
var str = 'hol';
var data = 'hola mundo';
if (data.length >= str.length && data.substring(0, str.length) == str)
    return true;
else
    return false;

0

W oparciu o odpowiedzi tutaj używam tej wersji, ponieważ wydaje się, że zapewnia najlepszą wydajność w oparciu o testy JSPerf (i jest funkcjonalnie kompletna, o ile mi wiadomo).

if(typeof String.prototype.startsWith != 'function'){
    String.prototype.startsWith = function(str){
        if(str == null) return false;
        var i = str.length;
        if(this.length < i) return false;
        for(--i; (i >= 0) && (this[i] === str[i]); --i) continue;
        return i < 0;
    }
}

Zostało to oparte na opensWith2 stąd: http://jsperf.com/startswith2/6 . Dodałem małe ulepszenie w celu drobnego ulepszenia wydajności, i od tego czasu dodałem również sprawdzanie, czy łańcuch porównawczy jest zerowy lub niezdefiniowany, i przekonwertowałem go, aby dodać do prototypu ciągu przy użyciu techniki w odpowiedzi CMS.

Zauważ, że ta implementacja nie obsługuje parametru „pozycja”, który jest wymieniony na tej stronie Mozilla Developer Network , ale i tak nie wydaje się być częścią propozycji ECMAScript.


0

Nie jestem pewien co do javascript, ale w maszynopisie zrobiłem coś takiego

var str = "something";
(<String>str).startsWith("some");

Myślę, że to też powinno działać na js. Mam nadzieję, że to pomoże!


-2

Jeśli pracujesz startsWith()i endsWith()musisz uważać na wiodące spacje. Oto kompletny przykład:

var str1 = " Your String Value Here.!! "; // Starts & ends with spaces    
if (str1.startsWith("Your")) { }  // returns FALSE due to the leading spaces…
if (str1.endsWith("Here.!!")) { } // returns FALSE due to trailing spaces…

var str2 = str1.trim(); // Removes all spaces (and other white-space) from start and end of `str1`.
if (str2.startsWith("Your")) { }  // returns TRUE
if (str2.endsWith("Here.!!")) { } // returns TRUE

3
Jest to bardzo niestandardowe zachowanie: ciąg „abc” NIE zaczyna się od „abc”. Mówiąc dokładniej, ECMA 6 nie zakłada żadnego przycinania łańcucha, więc białe spacje muszą dokładnie pasować, aby uzyskać dopasowanie StartWith.
Steve Hollasch,

3
Co ... jak to odpowiada na pytanie?
DCShannon

1
@DCShannon to nie jest. To niezrozumiały nonsens.
Mark Amery

2
@ SteveHollasch Moim celem było uświadomienie sobie każdego, kto szuka tego samego problemu, z którym się spotkałem. Podczas pracy z funkcjami startsWith()i endsWith()funkcjami musimy uważać na wiodące spacje . Nic więcej!
immayankmodi,

-3

Możesz także zwrócić wszystkich członków tablicy, które zaczynają się od ciągu, tworząc własny prototyp / rozszerzenie do prototypu tablicy, czyli

Array.prototype.mySearch = function (target) {
    if (typeof String.prototype.startsWith != 'function') {
        String.prototype.startsWith = function (str){
        return this.slice(0, str.length) == str;
      };
    }
    var retValues = [];
    for (var i = 0; i < this.length; i++) {
        if (this[i].startsWith(target)) { retValues.push(this[i]); }
    }
    return retValues;
};

I aby go użyć:

var myArray = ['Hello', 'Helium', 'Hideout', 'Hamster'];
var myResult = myArray.mySearch('Hel');
// result -> Hello, Helium
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.