我如何在JavaScript中编写等效的C#String.StartsWith
?
var haystack = 'hello world';
var needle = 'he';
haystack.startsWith(needle) == true
注意:这是一个老问题,正如评论中指出的ECMAScript 2015(ES6)引入了.startsWith
方法。但是,在撰写此更新时(2015)browser support is far from complete。
答案 0 :(得分:1711)
您可以使用ECMAScript 6的String.prototype.startsWith()
方法,但它是not yet supported in all browsers。您将需要使用填充/填充将其添加到不支持它的浏览器上。创建符合all the details laid out in the spec的实现有点复杂。如果你想要忠实的垫片,请使用:
String.prototype.startsWith
shim或String.prototype.startsWith
。一旦你对方法进行了调整(或者如果你只支持已经有它的浏览器和JavaScript引擎),你可以像这样使用它:
"Hello World!".startsWith("He"); // true
var haystack = "Hello world";
var prefix = 'orl';
haystack.startsWith(prefix); // false
答案 1 :(得分:1255)
.lastIndexOf
的另一种选择:
haystack.lastIndexOf(needle, 0) === 0
从[{1}}的索引haystack
开始,needle
出现0
,向后看haystack
。换句话说,它只会检查haystack
是否以needle
开头。
原则上,这应该比其他一些方法具有性能优势:
haystack
。答案 2 :(得分:584)
data.substring(0, input.length) === input
答案 3 :(得分:182)
没有辅助函数,只需使用正则表达式的.test
方法:
/^He/.test('Hello world')
使用动态字符串而不是硬编码字符串(假设字符串不包含任何正则表达式控制字符)来执行此操作:
new RegExp('^' + needle).test(haystack)
如果可能存在正则表达式控制字符出现在字符串中,您应该查看Is there a RegExp.escape function in Javascript?。
答案 4 :(得分:54)
最佳解决方案:
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 :
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
答案 5 :(得分:52)
我只是想补充一下我对此的看法。
我想我们可以这样使用:
var haystack = 'hello world';
var needle = 'he';
if (haystack.indexOf(needle) == 0) {
// Code if string starts with this substring
}
答案 6 :(得分:38)
以下是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
更快,更简洁,但不可读。
答案 7 :(得分:21)
同时查看underscore.string.js。它附带了一堆有用的字符串测试和操作方法,包括startsWith
方法。来自文档:
startsWith
_.startsWith(string, starts)
此方法会检查
string
是否以starts
开头。_("image.gif").startsWith("image") => true
答案 8 :(得分:15)
我最近问自己同样的问题 有多种可能的解决方案,这里有3个有效的解决方案:
s.indexOf(starter) === 0
s.substr(0,starter.length) === starter
s.lastIndexOf(starter, 0) === 0
(在看过Mark Byers' s 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;
}
我还没有遇到使用循环的最后一个解决方案 令人惊讶的是,这个解决方案的表现明显优于前三个解决方案 以下是为实现这一结论而执行的jsperf测试:http://jsperf.com/startswith2/2
和平
ps:ecmascript 6(和声)为字符串引入了原生的startsWith
方法
想想如果他们想到在初始版本中包含这个非常需要的方法,那么会节省多少时间。
<强>更新强>
正如Steve指出的那样(对此答案的第一个评论),如果给定的前缀比整个字符串短,则上述自定义函数将抛出错误。他修复了这个问题并添加了一个循环优化,可以在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;
}
答案 9 :(得分:11)
由于这是如此受欢迎,我认为值得指出的是,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 :(得分: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。 (确保检查可能胜过我的更新版本。)
答案 11 :(得分:2)
我刚刚了解了这个字符串库:
包含js文件,然后使用S
变量,如下所示:
S('hi there').endsWith('hi there')
它也可以通过安装在NodeJS中使用:
npm install string
然后将其作为S
变量:
var S = require('string');
网页上还有指向备用字符串库的链接,如果这个图书馆没有您喜欢的话。
答案 12 :(得分:1)
var str = 'hol';
var data = 'hola mundo';
if (data.length >= str.length && data.substring(0, str.length) == str)
return true;
else
return false;
答案 13 :(得分: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或未定义的检查,并将其转换为使用CMS答案中的技术添加到String原型。
请注意,此实现不支持此Mozilla Developer Network页面中提到的“position”参数,但这似乎不是ECMAScript提案的一部分。
答案 14 :(得分:0)
我不确定使用javascript,但是在打字稿中我做了类似
的操作var str = "something";
(<String>str).startsWith("some");
我猜它也应该在js上工作。 希望对您有所帮助!
答案 15 :(得分:0)
我基本上需要一种快速的方法来查找长针堆中是否有长针,除了最后一个字符外,它们非常相似。
这是我编写的代码,对于每个函数(拼接,子字符串,startsWith等),它们针对1.000.0001个字符的干草堆字符串(nestedString
)返回false和true时均进行测试,同时对它们进行伪造或1.000.000个字符的真实字符串(分别为testParentStringFalse
和testParentStringTrue
):
// 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)
}
我在 Chrome 75 , Firefox 67 , Safari 12 和 Opera 62 上运行了该基准测试。 / p>
我没有包括Edge和IE,因为我没有在这台计算机上使用它们,但是如果你们中的某人想要针对Edge和至少IE 9运行脚本并在此处共享输出,我会非常好奇结果。
请记住,您需要重新创建3个长字符串并将脚本保存在文件中,然后在浏览器中打开该脚本,因为在浏览器控制台上复制/粘贴将阻止该脚本,因为每个字符串的长度> = 1.000.000)
以下是输出:
Chrome 75(获胜substring
):
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(获胜indexOf
):
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({slice
赢得虚假结果,startsWith
赢得真实结果,就执行整个测试的总时间而言,Safari也是最快的):
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(substring
获胜。结果类似于Chrome,Opera基于Chromium和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}
事实证明,每个浏览器都有自己的实现细节(Opera,它基于Chrome的Chromium和Blink)。
当然,可以并且应该在不同的用例下进行进一步的测试(例如,当针比干草堆短时,当干草堆比针短时,等等),但是在我的情况下,我需要进行比较长字符串,想在这里分享。
答案 16 :(得分:0)
字符串对象具有startsWith,endsWith之类的方法,并且包含方法。
StartsWith检查给定的字符串是否以开头开头。
endsWith检查给定的字符串是否在结尾。
includes检查指定字符串是否存在于任何部分。
您可以在下面的youtube视频中找到这三者的完全区别
答案 17 :(得分:-2)
如果您正在使用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
答案 18 :(得分:-3)
您还可以通过为数组原型创建自己的原型/扩展来返回以字符串开头的数组的所有成员,也就是
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