Как проверить, является ли строка «StartsWith» другой строкой?

1627

Как мне написать эквивалент С# String.StartsWith в JavaScript?

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

//haystack.startsWith(needle) == true

Примечание. Это старый вопрос, и, как указано в комментариях, ECMAScript 2015 (ES6) ввел метод .startsWith. Однако на момент написания этого обновления (2015) поддержка браузера далека от завершения.

Теги:
string
startswith

17 ответов

1658
Лучший ответ

Вы можете использовать ECMAScript 6 String.prototype.startsWith(), но not но поддерживается во всех браузерах. Вы захотите использовать плагин / polyfill, чтобы добавить его в браузеры, которые его не поддерживают. Создание реализации, которая соответствует все детали, изложенные в спецификации, немного сложны, и версия, определенная в этом ответе, не будет выполняться; если вы хотите получить точную прокладку, используйте либо:

После того как вы настроили метод (или если вы только поддерживаете браузеры и движки JavaScript, которые уже есть), вы можете использовать его следующим образом:

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

var haystack = "Hello world";
var prefix = 'orl';
haystack.startsWith(prefix); // false
  • 1
    JSPerf с собственным startsWith : jsperf.com/js-startwith-prototype/8
  • 0
    @gtournie, почему запускается с одним из худших способов проверить, начинается ли строка со строки? (см. ваш комментарий здесь: stackoverflow.com/questions/646628/… ) вы с большим энтузиазмом относитесь к сравнению символа на символ. Я надеюсь, что компиляторы достаточно умны, чтобы НЕ генерировать строку для каждой строки [индекс], потому что, если вы просто напишите это: )
Показать ещё 5 комментариев
1165

Другая альтернатива .lastIndexOf:

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

Это выглядит назад через haystack для появления needle, начиная с индекса 0 от haystack. Другими словами, он проверяет, начинается ли haystack с needle.

В принципе, это должно иметь преимущества производительности по сравнению с некоторыми другими подходами:

  • Он не выполняет поиск по всему тегу haystack.
  • Он не создает новую временную строку и сразу же отбрасывает ее.
  • 1
    Не уверен, о каком случае @ rfcoder89 идет речь - jsfiddle.net/jkzjw3w2/1
  • 5
    @ rfcoder89 Обратите внимание, что второй параметр lastIndexOf: "aba".lastIndexOf ("a") равен 2, как вы "aba".lastIndexOf ("a", 0) , но "aba".lastIndexOf ("a", 0) равен 0, что правильно
Показать ещё 3 комментария
570
data.substring(0, input.length) === input
  • 3
    @ ANeves Я подозреваю, что это сильно зависит от браузера и используемых данных. См. Ответ Бена Уивера для реальных измерений. В браузере, в котором я сейчас работаю (Chrome 12.0.742 для Windows), подстрока выигрывает для успеха и готовит регулярные выражения для неудачи.
  • 4
    @cobbal Возможно. Но .lastIndexOf(input, 0) сравнивает первые N символов, тогда как .substring(0, input.length) === input подсчитывает N, подстраивает данные в длину N, а затем сравнивает эти N символов. Если нет оптимизации кода, эта вторая версия не может быть быстрее, чем другая. Не поймите меня неправильно, я никогда не найду ничего лучше, чем вы предлагаете. :)
Показать ещё 3 комментария
180

Без вспомогательной функции, просто используя regex .test метод:

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

Чтобы сделать это с динамической строкой, а не с жестко закодированной (предполагается, что строка не будет содержать никаких управляющих символов регулярного выражения):

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

Вы должны проверить Есть ли функция RegExp.escape в Javascript?, если существует вероятность того, что в строке появятся управляющие символы регулярного выражения.

  • 0
    Чтобы сделать выражение чувствительным к регистру, используйте /^he/i
52

Я просто хотел добавить свое мнение об этом.

Я думаю, мы можем просто так:

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

if (haystack.indexOf(needle) == 0) {
  // Code if string starts with this substring
}
  • 2
    Ответ Mark Byers был сравнен с @relfor для выполнения трех разных правильных подходов. Этот правильный подход не был одобрен, потому что он требует поиска по всей строке.
  • 0
    @ maxpolk Я думаю, indexOf прекратит поиск всей строки, когда найдет первый случай. Я проверил это.
Показать ещё 6 комментариев
42

Лучшее решение:

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

И вот концы, если вам это нужно:

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

Для тех, кто предпочитает прототипировать его в 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;
});

Применение:

"abc".startsWith("ab")
true
"c".ensdWith("c") 
true
  • 0
    Я думаю, что вы смешали lastIndexOf и indexOf в своих функциях - старты должны возвращать str.indexOf (word, 0) === 0;
  • 5
    @RichardMatheson проблема с использованием indexOf в том, что если ему не удастся сопоставить в начале, он продолжит поиск всей строки, в результате чего lastIndexOf начинается с длины слова и возвращается к нулю. Понял?
Показать ещё 1 комментарий
36

Вот небольшое улучшение для решения 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

Проверка, существует ли эта функция, если будущий браузер реализует ее в собственном коде или если она реализована другой библиотекой. Например, библиотека Prototype уже реализует эту функцию.

Использование ! немного быстрее и более кратким, чем === 0, хотя и не читается.

  • 1
    Это может стать проблемой: если уже реализованная реализация ведет себя не так, как у меня, это приведет к поломке моего приложения.
  • 2
    Это имеет проблему O (N), обсуждаемую здесь stackoverflow.com/questions/646628/javascript-startswith/…
Показать ещё 4 комментария
22

Также проверьте underscore.string.js. Он поставляется с множеством полезных методов тестирования строк и манипуляции, включая метод startsWith. Из документов:

начинается с _.startsWith(string, starts)

Этот метод проверяет, начинается ли string с starts.

_("image.gif").startsWith("image")
=> true
  • 1
    Мне нужно _.string.startsWith
15

Недавно я задал себе тот же вопрос.
Существует несколько возможных решений: 3 действительных:

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0 (добавлено после просмотра Mark Byers answer)
  • с использованием цикла:

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

Я не сталкивался с последним решением, которое использует использование цикла.
Удивительно, но это решение значительно превосходит первые 3. Вот тест jsperf, который я выполнил, чтобы прийти к такому выводу: http://jsperf.com/startswith2/2

Мир

ps: ecmascript 6 (гармония) вводит собственный метод startsWith для строк.
Подумайте, сколько времени было бы спасено, если бы они подумали о включении этого очень необходимого метода в первую версию.

Обновление

Как указал Стив (первый комментарий к этому ответу), вышеупомянутая пользовательская функция выдает ошибку, если данный префикс короче всей строки. Он исправил это и добавил оптимизацию цикла, которую можно просмотреть на http://jsperf.com/startswith2/4.

Обратите внимание, что есть 2 оптимизации циклов, которые включил Стив, первый из двух показал лучшую производительность, поэтому я опубликую этот код ниже:

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;
}
  • 0
    Смотрите последнюю версию Помимо ошибки в вышеупомянутой версии (она будет выдавать, если строка короче префикса), она также медленнее, чем более оптимизированная версия. См. Jsperf.com/startswith2/4 и jsperf.com/js-startswith/35 .
  • 0
    ^ Спасибо за указание на случай, когда строка короче префикса
Показать ещё 1 комментарий
10

Поскольку это настолько популярно, я считаю, что стоит отметить, что в ECMA 6 есть реализация этого метода, и в рамках подготовки к этому следует использовать "официальный" polyfill, чтобы предотвратить будущие проблемы и слезы.

К счастью эксперты из Mozilla предоставляют нам один:

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

Обратите внимание, что это имеет преимущество при грамотном игнорировании при переходе на ECMA 6.

5

Лучшее решение для работы - это прекратить использование вызовов библиотеки и просто признать, что вы работаете с двумя массивами. Выполненная вручную реализация является короткой и быстрее, чем любое другое решение, которое я видел здесь.

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

Для сравнения производительности (успех и сбой) см. http://jsperf.com/startswith2/4. (Убедитесь, что вы проверяете более поздние версии, которые, возможно, превзошли мои.)

2

Я только что узнал об этой строковой библиотеке:

http://stringjs.com/

Включите js файл, а затем используйте переменную S следующим образом:

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

Его также можно использовать в NodeJS, установив его:

npm install string

Затем требуя его как переменную S:

var S = require('string');

На веб-странице также есть ссылки на альтернативные библиотеки строк, если это не ваше воображение.

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

Я искал производительность, поэтому я запускал функции через jsperf. Я тестировал функции против сюжетных и поисковых строк различных размеров, и кажется, что все методы демонстрируют разную производительность различных входных данных; общая картина заключается в том, что производительность ухудшается по мере увеличения длины строки поиска.

Общий победитель оказывается методом substr(ing).

https://jsperf.com/javascript-string-startswith

0

Основываясь на ответах здесь, это версия, которую я использую сейчас, поскольку она, как представляется, дает лучшую производительность на основе тестирования JSPerf (и, насколько я знаю, функционально завершена).

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

Это было основано на startsWith2 отсюда: http://jsperf.com/startswith2/6. Я добавил небольшую настройку для небольшого улучшения производительности и с тех пор также добавил проверку на то, что строка сравнения равна null или undefined, и преобразует ее для добавления в прототип String с использованием метода ответа CMS.

Обратите внимание, что эта реализация не поддерживает параметр "позиция", который упоминается в этой странице Mozilla Developer Network, но это не по-видимому, являются частью предложения ECMAScript.

-1

Если вы работаете с startsWith() и endsWith(), тогда вы должны быть осторожны в ведущих пробелах. Вот полный пример:

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
    Это очень нестандартное поведение: строка «abc» НЕ начинается с «abc». Более конкретно, ECMA 6 не предполагает какого-либо обрезания строки, поэтому пробельные символы должны точно совпадать, чтобы получить совпадение startWith.
  • 3
    Что ... как это отвечает на вопрос?
Показать ещё 2 комментария
-3

Вы также можете вернуть все элементы массива, которые начинаются со строки, создав собственный прототип/расширение для прототипа массива, aka

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

И использовать его:

var myArray = ['Hello', 'Helium', 'Hideout', 'Hamster'];
var myResult = myArray.mySearch('Hel');
// result -> Hello, Helium

Ещё вопросы

Сообщество Overcoder
Наверх
Меню