题 如何检查字符串“StartsWith”是否是另一个字符串?


我怎么写相当于C#的 String.StartsWith 在JavaScript?

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

//haystack.startsWith(needle) == true

注意:这是一个老问题,正如ECMAScript 2015(ES6)的评论中所指出的那样 .startsWith 方法。但是,在撰写本次更新时(2015年) 浏览器支持远未完成


1547
2018-03-14 20:12


起源




答案:


你可以使用ECMAScript 6 String.prototype.startsWith() 方法,但它是 尚未在所有浏览器中支持。您将需要使用填充/填充将其添加到不支持它的浏览器上。创建符合的实现 规范中列出了所有细节 有点复杂,这个答案中定义的版本不会这样做;如果你想要忠实的垫片,请使用:

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

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

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

1655
2018-03-14 20:19



JSPerf与原生 startsWith: jsperf.com/js-startwith-prototype/8 - JimmyBoh
@gtournie为什么会启动它是测试字符串是否以字符串开头的最差方法之一? (见你的评论: stackoverflow.com/questions/646628/...你更热衷于比较每个角色的角色。我希望编译器足够聪明,不要为每个字符串[index]生成一个字符串,因为如果你只是写这个:character = string [0]它将分配一个对象,无限使用startsWith(startsWith将不会分配任何内存) ) - Martijn Scheffer
@MartijnScheffer:答案已被编辑多次,因为我回复并且现在完全不同(我删除了我的评论;)。我同意ECMAScript 6的startsWith方法是最好的方法。 - gtournie
@GrahamLaight,当你说'IE'支持时,大概是你的意思是Edge。 developer.mozilla.org/en/docs/Web/JavaScript/Reference/... - Marcus
@Marcus,如果我错了就道歉 - 我的信息来自: w3schools.com/jsref/jsref_startswith.asp - Graham Laight


另一种选择 .lastIndexOf

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

这看起来倒退了 haystack 发生的 needle 从索引开始 0 的 haystack。换句话说,它只检查是否 haystack 以。。开始 needle

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

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

1226
2018-01-02 16:14



不确定@ rfcoder89正在采取哪种情况 - jsfiddle.net/jkzjw3w2/1 - Gulfaraz Yasin
@ rfcoder89注意lastIndexOf的第二个参数: "aba".lastIndexOf ("a") 你指出是2,但是 "aba".lastIndexOf ("a", 0) 是0,这是正确的 - maxpolk
非常感谢。 String.startsWith在Android棒棒糖WebView上不起作用,但这个lastIndexOf片段确实有效! - Herman
同 lastIndexOf 从结尾到开头搜索字符串,以便搜索整个字符串:因此,对于要搜索的非常长的字符串,它的效率会降低。 - willy wonka
@willywonka不,如果你有0 startIndex就不是,它是从0 pos搜索的,这是唯一的检查。仅当fromIndex> = str.length时才搜索整个字符串。 - greene


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

569
2018-03-14 20:14



@ANeves我怀疑它在很大程度上取决于浏览器和使用的数据。请参阅Ben Weaver的实际测量答案。在我正在运行的浏览器上(Windows上的Chrome 12.0.742)子串获胜并获得成功并准备正则表达式失败。 - cobbal
@cobbal也许吧。但 .lastIndexOf(input, 0) 比较前N个字符,而 .substring(0, input.length) === input 计数N,将数据子串到N长度,然后比较这些N个字符。除非有代码优化,否则第二个版本不能比另一个快。不要误会我的意思,我永远找不到比你建议更好的东西。 :) - ANeves
@ANeves但是.lastIndexOf在一个将返回false的长字符串上将迭代整个字符串(O(N)),而.substring情况则迭代一个可能小得多的字符串。如果你期望多数成功或只有小输入,.lastIndexOf可能更快 - 否则.substring可能更快。如果输入长于被检查的字符串,则.substring也存在异常风险。 - Chris Moschini
@ChrisMoschini,别忘了Mark Byers的解决方案了 lastIndexOf 从索引0开始,而不是结束。最初,这也让我绊倒了。仍然,检查一个字符串的开头是一个常见的任务,JavaScript真的应该有一个适当的API,而不是你在这个页面上看到的所有习语和替代品,无论它们多么聪明。 - Randall Cook
我更喜欢cobbal对Mark的解决方案。即使mark更快,使用params也是一个令人印象深刻的技巧,与子串相比,它很难阅读。 - ThinkBonobo


没有辅助函数,只需使用正则表达式 .test 方法:

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

要使用动态字符串而不是硬编码字符串(假设字符串不包含任何正则表达式控制字符):

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

你应该看看 Javascript中是否有RegExp.escape函数? 如果存在正则表达式控制字符出现在字符串中的可能性。


180
2018-01-04 00:59





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

我想我们可以像这样使用:

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



通过@relfor比较了Mark Byers对三种不同正确方法的表现的回答。这种正确的方法不受欢迎,因为它需要搜索整个字符串。 - maxpolk
@maxpolk我想 indexOf 发现第一次出现时将停止搜索整个字符串。我检查了一下。 - Mr.D
如果在最开始时没有找到第一次出现,那么这种方法在继续寻找它的时间越长就开始变得越来越低效,可能会一直搜索直到它到达最后,而不是更早地放弃。由于存在低效率的可能性,因此在三种正确方法中不受青睐。 - maxpolk
@ Mr.D如果没有比赛? - momo
@momomo然后添加 else 码。 - Mr.D


最佳方案:

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

42
2018-04-26 21:56



我认为你的函数中混合了lastIndexOf和indexOf-- startsWith应该返回str.indexOf(word,0)=== 0; - Richard Matheson
@RichardMatheson使用indexOf的问题是,如果它在开始时匹配失败,它将继续搜索整个字符串,从而lastIndexOf从单词的长度开始并回到零。得到它了? - momo
啊,现在是有道理的 - 我没注意你使用的指数。非常好的技巧! - Richard Matheson


以下是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 Library已经实现了这个功能。

运用 ! 比...更快,更简洁 === 0 虽然不那么可读。


37
2018-05-27 02:54



这可能会成为一个问题:如果已经实现的实现与我自己的实现不同,这将破坏我的应用程序。 - Christoph Wurm
这具有此处讨论的O(N)问题 stackoverflow.com/questions/646628/javascript-startswith/... - Chris Moschini
用!有很混乱 - Jonny Leeds
-1;将此添加到 String.prototype 是一个坏主意,因为它不会接近遵守 规范 对于 String.prototype.startsWith。尝试使用ES6方法的任何代码如果你这样做都可能会失败;它可能会查看该方法是否已经定义,看到它(很糟糕,由你)并且不添加符合规范的垫片,导致以后的错误行为。 - Mark Amery
这不好。 - momo


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

以。。开始  _.startsWith(string, starts)

此方法检查是否 string 以。。开始 starts

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

21
2018-05-31 18:29



我需要 _.string.startsWith - Colonel Panic


我最近问自己同样的问题。
有多种可能的解决方案,这里有3个有效的解决方案:

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0 (看过马克拜尔斯之后补充道 回答
  • 使用循环:

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

我没有遇到使用循环的最后一个解决方案。
令人惊讶的是,这个解决方案的表现明显优于前三个。
这是我为达到这个结论而进行的jsperf测试: http://jsperf.com/startswith2/2

和平

ps:ecmascript 6(和谐)介绍了原生 startsWith 字符串的方法。
想想如果他们想到在初始版本中包含这个非常需要的方法,那么会节省多少时间。

更新

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

请注意,Steve包含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;
}

15
2018-05-17 09:07



查看最新版本。除了上述版本中的错误(如果字符串比前缀短,它将抛出),它也比更优化的版本慢。看到 jsperf.com/startswith2/4 和 jsperf.com/js-startswith/35。 - Steve Hollasch
^感谢指出字符串短于前缀的情况 - Raj Nathani
jsperf.com/startswith2/29 => startsWith5简洁,表现非常好=) - gtournie


由于这是如此受欢迎,我认为值得指出的是,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时被优雅地忽略。


10
2018-01-05 11:34



有缺陷,看 stackoverflow.com/a/36876507/961018 - momo