关于javascript:如何检查字符串是否是另一个字符串的开头?

How to check if a string “StartsWith” another string?

我如何在javascript中编写C的String.StartsWith的等价物?

1
2
3
4
var haystack = 'hello world';
var needle = 'he';

haystack.startsWith(needle) == true

注:这是一个古老的问题,正如ECMAScript 2015(ES6)在评论中所指出的,引入了.startsWith方法。但是,在编写此更新(2015年)时,浏览器支持还远未完成。


您可以使用ecmascript 6的String.prototype.startsWith()方法,但在所有浏览器中都不支持这种方法。您将要使用填充/多边形填充将其添加到不支持它的浏览器中。创建一个符合规范中列出的所有详细信息的实现有点复杂,而这个答案中定义的版本将不起作用;如果您想要一个忠实的填充程序,请使用以下任一方法:

  • Matthias Bynens's String.prototype.startsWith垫片,或
  • ES6垫片,其垫片尽可能多地符合ES6规格,包括String.prototype.startsWith

一旦你填充了这个方法(或者如果你只支持已经拥有它的浏览器和JavaScript引擎),你就可以这样使用它:

1
2
3
4
5
"Hello World!".startsWith("He"); // true

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


另一个与.lastIndexOf的替代方案:

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

这回顾了haystack中的needle的出现,从haystack的索引0开始。换句话说,它只检查haystack是否以needle开头。

原则上,这应该比其他一些方法具有性能优势:

  • 它不搜索整个haystack
  • 它不会创建新的临时字符串,然后立即丢弃它。


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


如果没有助手函数,只需使用regex的.test方法:

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

要使用动态字符串而不是硬编码字符串进行此操作(假定该字符串不包含任何regexp控制字符):

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

您应该检查一下javascript中是否有regexp.escape函数?如果有可能在字符串中出现regexp控制字符。


最佳解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

如果你也需要的话,这里是endswith:

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

对于那些喜欢将其原型化为字符串的用户:

1
2
3
4
5
6
7
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;
});

用途:

1
2
3
4
"abc".startsWith("ab")
true
"c".ensdWith("c")
true


我只是想补充一下我对此的看法。

我想我们可以这样使用:

1
2
3
4
5
6
var haystack = 'hello world';
var needle = 'he';

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


以下是CMS解决方案的一个小改进:

1
2
3
4
5
6
7
8
9
10
11
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

检查该函数是否已存在,以防将来的浏览器使用本机代码实现它,或者是否由其他库实现。例如,原型库已经实现了这个函数。

使用!=== 0稍微快一些,也更简洁一些,尽管不可读。


还可以查看underline.string.js。它附带了一系列有用的字符串测试和操作方法,包括startsWith方法。来自文档:

startsWith _.startsWith(string, starts)

This method checks whether string starts with starts.

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


我最近也问自己同样的问题。有多种可能的解决方案,以下是3种有效的解决方案:

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0(见Mark Byers回答后增加)
  • 使用循环:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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个。下面是我为得出这个结论而进行的jspef测试:http://jspef.com/startswith2/2

和平

ps:ecmascript 6(Harmony)为字符串引入了一种本地的startsWith方法。想想如果他们考虑在初始版本中包含这个非常需要的方法,会节省多少时间。

更新

正如Steve所指出的(对这个答案的第一条评论),如果给定的前缀比整个字符串短,上面的自定义函数将抛出一个错误。他修复了这个问题,并添加了一个循环优化,可以在http://jspef.com/startswith2/4上查看。

请注意,Steve提供了两种循环优化,其中第一种优化的性能更好,因此我将在下面发布该代码:

1
2
3
4
5
6
7
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;
}


由于这是如此流行,我认为值得指出的是,在ECMA 6中有一个方法的实现,为了准备这个方法,应该使用"官方"polyfill,以防止将来的问题和眼泪。

幸运的是,Mozilla的专家为我们提供了一个:

https://developer.mozilla.org/de/docs/web/javascript/reference/global_objects/string/startswith

1
2
3
4
5
6
if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position) {
        position = position || 0;
        return this.indexOf(searchString, position) === position;
    };
}

请注意,在过渡到ECMA 6时,这有被优雅地忽略的优势。


最好的性能解决方案是停止使用库调用,只需认识到您使用的是两个数组。手摇实现既短又快,比我在这里看到的所有其他解决方案都快。

1
2
3
4
5
6
7
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://jspef.com/startswith2/4。(确保您检查了可能胜过我的更高版本。)


我刚刚了解了这个字符串库:

http://stringjs.com网站/

包括JS文件,然后使用S变量,如下所示:

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

它也可以通过安装在nodejs中使用:

1
npm install string

然后要求它作为S变量:

1
var S = require('string');

如果您不喜欢,网页也有指向备用字符串库的链接。


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

基于这里的答案,这是我现在使用的版本,因为它似乎提供了基于JSPerf测试的最佳性能(据我所知,它在功能上是完整的)。

1
2
3
4
5
6
7
8
9
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://jspef.com/startswith2/6。我为一个微小的性能改进添加了一个小的调整,然后还添加了对比较字符串是否为空或未定义的检查,并将其转换为使用CMS答案中的技术添加到字符串原型中。

请注意,此实现不支持此Mozilla开发者网络页面中提到的"position"参数,但这似乎不属于EcmaScript建议的一部分。


如果您使用的是startsWith()endsWith(),那么您必须小心引导空间。下面是一个完整的例子:

1
2
3
4
5
6
7
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


您还可以通过为数组原型创建自己的原型/扩展来返回以字符串开头的数组的所有成员,也就是

1
2
3
4
5
6
7
8
9
10
11
12
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;
};

并使用它:

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