문자열이 다른 문자열을 "시작"하는지 확인하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/646628

  •  22-07-2019
  •  | 
  •  

문제

C#의 동등한 것을 어떻게 작성합니까? String.StartsWith 자바 스크립트로?

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

haystack.startsWith(needle) == true

참고 : 이것은 오래된 질문이며, 의견에서 지적한 바와 같이 ECMAScript 2015 (ES6)가 소개했습니다. .startsWith 방법. 그러나이 업데이트를 작성할 때 (2015) 브라우저 지원은 완전하지 않습니다.

도움이 되었습니까?

해결책

ECMAScript 6을 사용할 수 있습니다 String.prototype.startsWith() 방법, 그러나 그것은입니다 모든 브라우저에서 아직 지원되지는 않습니다. Shim/Polyfill을 사용하여 지원하지 않는 브라우저에 추가하고 싶을 것입니다. 준수하는 구현을 만듭니다 사양에 포함 된 모든 세부 사항 조금 복잡합니다. 충실한 심을 원한다면 다음을 사용하십시오.

이 방법을 바꾸면 (또는 이미 가지고있는 브라우저 및 JavaScript 엔진 만 지원하는 경우) 다음과 같이 사용할 수 있습니다.

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

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

다른 팁

또 다른 대안 .lastIndexOf:

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

이것은 거꾸로 봅니다 haystack 발생합니다 needle 색인에서 시작합니다 0haystack. 다시 말해, 그것은 단지 확인합니다 haystack 시작합니다 needle.

원칙적으로 이것은 다른 접근 방식에 비해 성능 이점이 있어야합니다.

  • 전체를 검색하지 않습니다 haystack.
  • 새 임시 문자열을 생성 한 다음 즉시 버리지 않습니다.
data.substring(0, input.length) === input

도우미 기능이 없으면 Regex를 사용합니다 .test 방법:

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

하드 코딩 된 문자열이 아닌 동적 문자열 로이 작업을 수행하려면 (문자열에 Regexp 컨트롤 문자가 포함되어 있지 않다고 가정) :

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

체크 아웃해야합니다 JavaScript에 Regexp.escape 함수가 있습니까? 가능성이 존재하는 경우 regexp 컨트롤 문자가 문자열에 나타납니다.

최상의 솔루션 :

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.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

나는 이것에 대한 나의 의견을 추가하고 싶었다.

우리는 다음과 같이 사용할 수 있다고 생각합니다.

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

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

다음은 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

향후 브라우저가 기본 코드로 구현하거나 다른 라이브러리에서 구현되는 경우 기능이 이미 존재하는지 확인합니다. 예를 들어, 프로토 타입 라이브러리는이 기능을 이미 구현합니다.

사용 ! 보다 약간 빠르고 간결합니다 === 0 읽기 쉬운 것은 아니지만.

또한 체크 아웃하십시오 aUndscore.string.js. 유용한 문자열 테스트 및 조작 방법이 포함되어 있습니다. startsWith 방법. 문서에서 :

시작합니다 _.startsWith(string, starts)

이 방법은 여부를 확인합니다 string 시작합니다 starts.

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

나는 최근에 나 자신에게 같은 질문을했다.
여러 가지 가능한 솔루션이 있습니다. 여기에 3 가지 유효한 솔루션이 있습니다.

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0 (Mark Byers 's를 본 후 추가되었습니다 대답)
  • 루프 사용 :

    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

평화

추신 : ECMAScript 6 (Harmony)는 네이티브를 소개합니다. 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;
}

이것은 매우 인기가 있기 때문에 ECMA 6에는이 방법에 대한 구현이 있다는 것을 지적 할 가치가 있다고 생각합니다. 그리고 미래의 문제와 눈물을 예방하기 위해 '공식'폴리 필을 사용해야합니다.

운 좋게도 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으로의 전환에 대해 우아하게 무시할 수 있다는 이점이 있습니다.

최상의 성능 솔루션은 라이브러리 통화 사용을 중단하고 두 배열로 작업하고 있음을 인식하는 것입니다. 손으로 묶은 구현은 내가 본 다른 모든 솔루션보다 짧고 빠릅니다.

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. (나중에 나올 수있는 나중에 버전을 확인하십시오.)

방금이 문자열 라이브러리에 대해 배웠습니다.

http://stringjs.com/

JS 파일을 포함시킨 다음 사용하십시오 S 다음과 같은 변수 :

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

Nodejs에서 설치하여 사용할 수 있습니다.

npm install string

그런 다음 그것을 요구합니다 S 변하기 쉬운:

var S = require('string');

웹 페이지에는 대체 문자열 라이브러리에 대한 링크가 있습니다.

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

여기의 답변을 바탕으로 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의 답변의 기술을 사용하여 문자열 프로토 타입에 추가하도록 변환했습니다.

이 구현은 이것에 언급 된 "위치"매개 변수를 지원하지 않습니다. 모질라 개발자 네트워크 페이지이지만 어쨌든 ECMAScript 제안의 일부가 아닌 것 같습니다.

JavaScript는 확실하지 않지만 TypeScript에서는 같은 것을했습니다.

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

JS에서도 작동해야한다고 생각합니다. 도움이되기를 바랍니다!

  1. 질문은 조금 오래되었지만 여기에 제공된 모든 답변과 Jim Buck이 공유 한 JSPERF를 기반으로 한 벤치 마크를 보여주기 위해이 답을 작성하고 싶었습니다.

나는 기본적으로 긴 바늘이 긴 건초 더미 내에 있는지 여부를 찾는 빠른 방법이 필요했고 마지막 캐릭터를 제외하고는 매우 유사합니다.

다음은 각 기능 (스플 라이스, 하위 문자, 시작 등)에 대해 Haystack 문자열에 대해 False와 True를 반환 할 때 테스트 한 코드입니다.nestedString) 1.000.0001 자 및 허위 또는 진실한 바늘 문자열 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)
}

이 벤치 마크 테스트를 실행했습니다 크롬 75, Firefox 67, 사파리 12 그리고 오페라 62.

나는이 기계에 그것들을 가지고 있지 않기 때문에 Edge와 IE를 포함시키지 않았지만, 당신의 누군가가 Edge에 대해 스크립트를 실행하고 적어도 9 9에 대해 스크립트를 실행하고 여기에서 출력을 공유하고 싶다면 결과를보고 매우 궁금합니다.

3 개의 긴 문자열을 재현하고 파일에 스크립트를 저장 한 다음 브라우저에서 열린 브라우저의 복사/붙여 넣기가 각 문자열의 길이가> = 1.000.000이므로 차단할 때 브라우저에서 열립니다.

출력은 다음과 같습니다.

크롬 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}

사파리 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}"

오페라 62 (substring 승리. 결과는 Chrome과 유사하며 오페라가 크롬 및 깜박임을 기반으로하기 때문에 놀라지 않습니다.)

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}

모든 브라우저에는 자체 구현 세부 정보가 있습니다 (Chrome의 크롬 및 깜박임을 기반으로하는 Opera는 분리됩니다).

물론, 다른 사용 사례에 대한 추가 테스트는 수행 될 수 있고 수행해야합니다 (예 : 바늘이 건초 더미에 비해 바늘이 실제로 짧은 경우, 건초 더미가 바늘보다 짧은 경우 등). 그러나 제 경우에는 매우 긴 줄을 비교하고 비교해야했습니다. 여기에서 공유하고 싶었습니다.

당신이 함께 일하는 경우 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

또한 배열 프로토 타입에 자신의 프로토 타입 / 확장을 만들어 문자열로 시작하는 배열의 모든 멤버를 반환 할 수 있습니다.

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top