문자열에서 문자열 발생을 계산하는 방법은 무엇입니까?


608

다른 문자열에서 특정 문자열이 발생하는 횟수를 계산하는 방법은 무엇입니까? 예를 들어, 이것은 자바 스크립트에서하려고하는 것입니다.

var temp = "This is a string.";
alert(temp.count("is")); //should output '2'

19
겹치는 인스턴스 를 허용하는지 여부에 따라 다릅니다 ( 예 : var t = "sss"; 위 문자열에 몇 개의 하위 문자열 "ss"인스턴스가 있습니까? 1 또는 2? 각 인스턴스를 뛰어 넘거나 포인터를 문자별로 이동하여 하위 문자열을 찾으십니까?
Tim

4
이 질문의 답변에 대한 개선 된 벤치 마크 : jsperf.com/string-ocurrence-split-vs-match/2 (Kazzkiq의 벤치 마크 기준).
idmean

답변:


1028

g(짧은 정규 표현식에서 글로벌은 ) 단지 첫 번째 항목을 찾을 것이 아니라 전체 문자열을 검색 말한다. 이것은 is두 번 일치합니다 .

var temp = "This is a string.";
var count = (temp.match(/is/g) || []).length;
console.log(count);

일치하는 항목이 없으면 다음을 반환합니다 0.

var temp = "Hello World!";
var count = (temp.match(/is/g) || []).length;
console.log(count);


3
현대적이고 우아하지만 Vitimtk의 솔루션은 훨씬 더 효율적입니다. 그의 코드에 대해 어떻게 생각하십니까?
TruMan1

5
이 질문에 가장 잘 대답합니다. 누군가가 "정규식없이 특별한 경우에 어떻게 10 배 빠르게 할 수 있을까?"
Dzhaughn

121
고마워요 count = (str.match(/is/g) || []).length. 경기가 없으면 처리하려고 했어요 .
Matt

6
유스 케이스가 설명하는 것처럼 문자열이 인수로 일치하지 않기 때문에이 답변이 질문과 올바르게 일치한다고 생각하지 않습니다. 물론 RegExp생성자를 사용 하고 원하는 문자열을 전달 하여 정규 표현식을 동적으로 만들 수 있지만이 경우 모든 메타 문자를 이스케이프해야합니다. 이 시나리오에서는 순수한 문자열 접근 방식이 바람직합니다.
ZER0

3
맷의 대답이 답에 있어야합니다!
Senči

240
/** Function that count occurrences of a substring in a string;
 * @param {String} string               The string
 * @param {String} subString            The sub string to search for
 * @param {Boolean} [allowOverlapping]  Optional. (Default:false)
 *
 * @author Vitim.us https://gist.github.com/victornpb/7736865
 * @see Unit Test https://jsfiddle.net/Victornpb/5axuh96u/
 * @see http://stackoverflow.com/questions/4009756/how-to-count-string-occurrence-in-string/7924240#7924240
 */
function occurrences(string, subString, allowOverlapping) {

    string += "";
    subString += "";
    if (subString.length <= 0) return (string.length + 1);

    var n = 0,
        pos = 0,
        step = allowOverlapping ? 1 : subString.length;

    while (true) {
        pos = string.indexOf(subString, pos);
        if (pos >= 0) {
            ++n;
            pos += step;
        } else break;
    }
    return n;
}

용법

occurrences("foofoofoo", "bar"); //0

occurrences("foofoofoo", "foo"); //3

occurrences("foofoofoo", "foofoo"); //1

allowOverlapping

occurrences("foofoofoo", "foofoo", true); //2

성냥:

  foofoofoo
1 `----´
2    `----´

단위 테스트

기준

나는 벤치 마크 테스트를했고 내 기능은 gumbo가 게시 한 정규 표현식 일치 기능보다 10 배 이상 빠릅니다. 내 테스트 문자열의 길이는 25 자입니다. 'o'라는 문자가 2 번 나타납니다. Safari에서 100,000 회 실행했습니다.

사파리 5.1

벤치 마크> 총 실행 시간 : 5617ms (정규 표현식)

벤치 마크> 총 실행 시간 : 881ms (내 기능 6.4 배 빠름)

Firefox 4

벤치 마크> 총 실행 시간 : 8547ms (Rexexp)

벤치 마크> 총 실행 시간 : 634ms (내 기능 13.5 배 빠름)


편집 : 내가 변경 한 사항

  • 캐시 된 부분 문자열 길이

  • 문자열에 타입 캐스팅을 추가했습니다.

  • 선택적 'allowOverlapping'매개 변수 추가

  • ""빈 부분 문자열 경우에 대한 올바른 출력을 수정했습니다.

요점

5
Safari 5 에서이 테스트를 반복하고 작은 (100b) 문자열로 비슷한 결과를 얻었지만 더 큰 문자열 (16kb)로 정규식이 더 빨리 실행되었습니다. 1,000,000이 아닌 1 회 반복의 경우 어쨌든 차이는 밀리 초보다 짧았으므로 내 투표는 정규식에 전달됩니다.
arlomedia

2
+1, substring.length거의 모든 루프를 점검 하고 있습니다.while
ajax333221

1
@ ajax333221 OMG 당신은 내 마음을 읽고, 나는 며칠 전이 개선했고, 내가 편집을 내 대답 가고 있었다 jsperf.com/count-string-occurrence-in-string
Vitim.us

4
success-equation.com/mind_reader.html 에서 사용중인 코드를 찾았습니다 . 프로그래머가 거기에 참조를 두는 것이 정말 좋았습니다.
Bruno Kim

3
@DanielZuzevich는 유형을 String으로 강제 변환하고 occurrences(11,1) //2여전히 작동 할 경우를 대비합니다 . (유형을 확인하고 toString ()을 호출하는 대신이 방법을 사용하는 것이 더 빠릅니다 )
Vitim.us

112
function countInstances(string, word) {
   return string.split(word).length - 1;
}

4
이는 안전하지 않거나 부정확 한 접근 방식입니다 (예 :) countInstances("isisisisisis", "is") === 0.
Nick Craver

5
@Antal-크롬의 이전 베타 빌드에서 버그처럼 보이며 최신 버전으로 업데이트 한 후에도 작동하지만 여전히이 방법을 피할 수 있습니다.
Nick Craver

28
이것은 나에게 완벽하게 유효한 솔루션처럼 보입니다.
Gregor Schmidt

2
호기심에서 @NickCraver, 왜이 방법을 피하고 싶습니까? (베타 브라우저의 버그 이외)
Jonny Lin

6
@JonnyLin 그것은 대안이없는 경우에 즉시 버릴 필요가없는 불필요한 할당을 만듭니다. 데이터에 따라 매우 큰 것입니다.
Nick Craver

88

당신은 이것을 시도 할 수 있습니다 :

var theString = "This is a string.";
console.log(theString.split("is").length - 1);


14
단순화를 위해 +1 하고 내 테스트에 따라이 솔루션 다른 솔루션 보다 ~ 10 배 빠르게 실행됩니다 !
Claudio Holanda

예를 들어, 나는 두 개의 "is"를 가지고 있으며 각각의 위치를 ​​어떻게 알 수 있습니까?
rapidoodle

@ Orbit의 답변에서 논의했듯이 사람들은 이전 버전의 Chrome에서 다른 결과를 얻고 있습니다. 이 방법을 사용하면 약간 조심해야 할 것입니다.
mgthomas99

그리고 변수와 함께 사용할 수도 있습니다 : theString.split(myvar).length - 1간단한 정규식으로 는 불가능합니다
Steffan

4
이 @Orbit 's의 대답 ... 3 년 후에
codidact.com로 이동 aloisdg

33

내 해결책 :

var temp = "This is a string.";

function countOcurrences(str, value) {
  var regExp = new RegExp(value, "gi");
  return (str.match(regExp) || []).length;
}

console.log(countOcurrences(temp, 'is'));


5
아마도 (str.match (regExp) || []). length;를 반환하는 것이 좋습니다. 그렇게하면 정규 표현식을 두 번 평가하지 않습니까?
aikeru

2
당신은 또한 당신의 문자열 또는 촉각 근 필요 countOcurrences('Hello...','.')==8하지 3
Vitim.us

19

match이러한 기능을 정의 하는 데 사용할 수 있습니다 .

String.prototype.count = function(search) {
    var m = this.match(new RegExp(search.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "g"));
    return m ? m.length:0;
}

1
JS의 검색 의미와 균일하게하려면 리턴 라인은입니다 return m ? m.length:-1;.
Conor O'Brien

문자열이 "["이거나 Regex에서 특별한 의미가있는 항목을 계산하는 경우 오류가 발생하기 때문에 위의 다른 정규식 솔루션보다 낫습니다.
programmer5000

11

비정규 버전 :

 var string = 'This is a string',
    searchFor = 'is',
    count = 0,
    pos = string.indexOf(searchFor);

while (pos > -1) {
    ++count;
    pos = string.indexOf(searchFor, ++pos);
}

console.log(count);   // 2


1. 그것은 단지 하나의 문자의 검색의도 미묘한 2.에도 영업 이익은 요청 is발행 수
vladkras

1
이것은 아마도 가장 빠른 구현 일 것입니다. 그러나 "++ pos"를 "pos + = searchFor.length"로
바꾸면



8

가장 빠른 기능입니다!

왜 더 빠릅니까?

  • char로 char을 검사하지 않습니다 (1 예외)
  • while을 사용하고 길이를 확인하고 2 var를 증가시키는 for 루프에 대해 1 var (char count var) 대 a를 증가시킵니다 (보통 var i 및 char count를 갖는 var)
  • 더 적은 변수를 사용합니다.
  • 정규식을 사용하지 않습니다!
  • (희망적으로) 고도로 최적화 된 기능을 사용합니다
  • 모든 작업은 가능한 한 결합되어 여러 작업으로 인한 속도 저하를 방지

    String.prototype.timesCharExist=function(c){var t=0,l=0,c=(c+'')[0];while(l=this.indexOf(c,l)+1)++t;return t};

느리고 읽기 쉬운 버전은 다음과 같습니다.

    String.prototype.timesCharExist = function ( chr ) {
        var total = 0, last_location = 0, single_char = ( chr + '' )[0];
        while( last_location = this.indexOf( single_char, last_location ) + 1 )
        {
            total = total + 1;
        }
        return total;
    };

이것은 카운터, 긴 var 이름 및 1 var의 오용으로 인해 느립니다.

사용하려면 간단히 다음을 수행하십시오.

    'The char "a" only shows up twice'.timesCharExist('a');

편집 : (2013/12/16)

Opera 12.16 이상에서는 사용하지 마십시오! 정규식 솔루션보다 거의 2.5 배 더 많이 걸립니다!

크롬 에서이 솔루션은 1,000,000 문자의 경우 14ms에서 20ms 사이입니다.

정규식 솔루션은 같은 양으로 11-14ms가 걸립니다.

기능 (외부 String.prototype)을 사용하는 데 약 10-13ms가 걸립니다.

사용 된 코드는 다음과 같습니다.

    String.prototype.timesCharExist=function(c){var t=0,l=0,c=(c+'')[0];while(l=this.indexOf(c,l)+1)++t;return t};

    var x=Array(100001).join('1234567890');

    console.time('proto');x.timesCharExist('1');console.timeEnd('proto');

    console.time('regex');x.match(/1/g).length;console.timeEnd('regex');

    var timesCharExist=function(x,c){var t=0,l=0,c=(c+'')[0];while(l=x.indexOf(c,l)+1)++t;return t;};

    console.time('func');timesCharExist(x,'1');console.timeEnd('func');

모든 솔루션의 결과는 100,000이어야합니다!

참고 :이 함수가 1 문자 이상을 계산하도록하려면 위치를 c=(c+'')[0]로 변경하십시오c=c+''


1
프로토 타입은 예였습니다! 원하는대로 기능을 사용할 수 있습니다! 이 작업을 수행 할 수도 있습니다. var timesFunctionExist = function (x, c) {var t = 0, l = 0, c = (c + '') [0]; while (l = x.indexOf (c, l) +1 ) ++ t; 반환 t}); alert (timesCharExist ( '문자 "a"는 두 번만 나타남', 'a')) ;! (이것은 프로토 타입을 엉망으로 만들지 않는 원인이 조금 더 빨라질 것입니다). 내가 틀렸다고 생각하면 나에게 바위를 던지기 전에 그것을 보여주지 않겠습니까? 내 기능이 짜증 나는 것을 증명하고 나는 그것을 받아 들일 것이다. 테스트 사례를 보여주세요. 그리고 vars의 길이는 속도에 영향을 미칩니다. 테스트 할 수 있습니다.
Ismael Miguel


4

정규식의 목적은와는 많이 다릅니다 indexOf. indexOf정규 표현식에서 와일드 카드를 사용할 수있는 동안 특정 문자열의 발생을 찾기 만하면 실제 문자를 지정하지 않고 단어에서 대문자 [A-Z]를 찾을 있습니다.

예:

 var index = "This is a string".indexOf("is");
 console.log(index);
 var length = "This is a string".match(/[a-z]/g).length;
 // where [a-z] is a regex wildcard expression thats why its slower
 console.log(length);


3

슈퍼 듀퍼 낡았지만 오늘 이와 같은 일을해야했고 나중에 확인해야한다고 생각했습니다. 나를 위해 아주 빨리 작동합니다.

String.prototype.count = function(substr,start,overlap) {
    overlap = overlap || false;
    start = start || 0;

    var count = 0, 
        offset = overlap ? 1 : substr.length;

    while((start = this.indexOf(substr, start) + offset) !== (offset - 1))
        ++count;
    return count;
};

3
       var myString = "This is a string.";
        var foundAtPosition = 0;
        var Count = 0;
        while (foundAtPosition != -1)
        {
            foundAtPosition = myString.indexOf("is",foundAtPosition);
            if (foundAtPosition != -1)
            {
                Count++;
                foundAtPosition++;
            }
        }
        document.write("There are " + Count + " occurrences of the word IS");

참조 :- 단계별 설명을 위해 문자열하위 문자열이 나타나는 횟수를 계산 하십시오 .


3

위의 @ Vittim.us 답변을 기반으로합니다. 나는 그의 방법이 제공하는 제어 기능을 좋아하여 쉽게 확장 할 수 있지만 문장 부호를 지원하여 대소 문자를 구분하지 않고 전체 단어에 대한 일치를 제한해야했습니다. (예 : "목욕탕"은 "목욕탕"에 있지만 "목욕탕"에 있지 않음)

구두점 정규 표현식은 https://stackoverflow.com/a/25575009/497745 에서 가져 왔습니다 ( 정규 표현식을 사용하여 JavaScript의 문자열에서 모든 구두점을 제거 하려면 어떻게해야합니까? )

function keywordOccurrences(string, subString, allowOverlapping, caseInsensitive, wholeWord)
{

    string += "";
    subString += "";
    if (subString.length <= 0) return (string.length + 1); //deal with empty strings

    if(caseInsensitive)
    {            
        string = string.toLowerCase();
        subString = subString.toLowerCase();
    }

    var n = 0,
        pos = 0,
        step = allowOverlapping ? 1 : subString.length,
        stringLength = string.length,
        subStringLength = subString.length;

    while (true)
    {
        pos = string.indexOf(subString, pos);
        if (pos >= 0)
        {
            var matchPos = pos;
            pos += step; //slide forward the position pointer no matter what

            if(wholeWord) //only whole word matches are desired
            {
                if(matchPos > 0) //if the string is not at the very beginning we need to check if the previous character is whitespace
                {                        
                    if(!/[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&\(\)*+,\-.\/:;<=>?@\[\]^_`{|}~]/.test(string[matchPos - 1])) //ignore punctuation
                    {
                        continue; //then this is not a match
                    }
                }

                var matchEnd = matchPos + subStringLength;
                if(matchEnd < stringLength - 1)
                {                        
                    if (!/[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&\(\)*+,\-.\/:;<=>?@\[\]^_`{|}~]/.test(string[matchEnd])) //ignore punctuation
                    {
                        continue; //then this is not a match
                    }
                }
            }

            ++n;                
        } else break;
    }
    return n;
}

버그 나 개선점을 발견하면이 답변을 수정하고 리팩터링하십시오.


3

미래 에이 스레드를 찾는 사람에게는 일반화 된 연산자와 같은 정규 표현식 연산자를 질식시키기 때문에 허용 된 답변이 일반화하면 항상 올바른 값을 반환하지는 않습니다. $ and와. . 다음은 모든 바늘을 처리 수있는 더 나은 버전입니다 .

function occurrences (haystack, needle) {
  var _needle = needle
    .replace(/\[/g, '\\[')
    .replace(/\]/g, '\\]')
  return (
    haystack.match(new RegExp('[' + _needle + ']', 'g')) || []
  ).length
}

3

function get_occurrence(varS,string){//Find All Occurrences
        c=(string.split(varS).length - 1);
        return c;
    }
    temp="This is a string.";
    console.log("Total Occurrence is "+get_occurrence("is",temp));

get_occurrence (varS, string)를 사용하여 문자열에서 문자와 문자열을 모두 찾습니다.


2

시도 해봐

<?php 
$str = "33,33,56,89,56,56";
echo substr_count($str, '56');
?>

<script type="text/javascript">
var temp = "33,33,56,89,56,56";
var count = temp.match(/56/g);  
alert(count.length);
</script>


2

아무도 이것을 볼 수는 없지만 재귀와 화살표 기능을 한 번에 다시 가져 오는 것이 좋습니다 (멋지게 의도 된 것)

String.prototype.occurrencesOf = function(s, i) {
 return (n => (n === -1) ? 0 : 1 + this.occurrencesOf(s, n + 1))(this.indexOf(s, (i || 0)));
};


1

이제 이것은 내가 겪은 아주 오래된 스레드이지만 많은 사람들이 대답을 푸시함에 따라이 간단한 코드로 누군가를 도울 수있는 희망이 있습니다.

var search_value = "This is a dummy sentence!";
var letter = 'a'; /*Can take any letter, have put in a var if anyone wants to use this variable dynamically*/
letter = letter && "string" === typeof letter ? letter : "";
var count;
for (var i = count = 0; i < search_value.length; count += (search_value[i++] == letter));
console.log(count);

그것이 가장 빠른 해결책인지 확실하지 않지만 단순성과 정규 표현식을 사용하지 않기 위해 선호했습니다 (나는 단지 그것들을 사용하는 것을 좋아하지 않습니다!)


1

이 함수는 텍스트에서 단어의 발생 횟수를 반환합니다.

참고 우리는 말씀과 텍스트의 (... 대문자 자본) 어떤 형식 발생 횟수를 계산하기 위해와 toLowerCase를 사용

wordCount(text, word) {
    if (!text || !word) {
      return 0;
    }
    text = text.toLowerCase();
    word = word.toLowerCase();
    return ( text.split( word ).length - 1 );
}

0

Leandro Batista에 대한 답변 : 정규식에 문제가 있습니다.

 "use strict";
 var dataFromDB = "testal";
 
  $('input[name="tbInput"]').on("change",function(){
	var charToTest = $(this).val();
	var howManyChars = charToTest.length;
	var nrMatches = 0;
	if(howManyChars !== 0){
		charToTest = charToTest.charAt(0);
		var regexp = new RegExp(charToTest,'gi');
		var arrMatches = dataFromDB.match(regexp);
		nrMatches = arrMatches ? arrMatches.length : 0;
	}
		$('#result').html(nrMatches.toString());

  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
What do you wanna count <input type="text" name="tbInput" value=""><br />
Number of occurences = <span id="result">0</span>
</div>


0

var countInstances = function(body, target) {
  var globalcounter = 0;
  var concatstring  = '';
  for(var i=0,j=target.length;i<body.length;i++){
    concatstring = body.substring(i-1,j);
    
    if(concatstring === target){
       globalcounter += 1;
       concatstring = '';
    }
  }
  
  
  return globalcounter;
 
};

console.log(   countInstances('abcabc', 'abc')   ); // ==> 2
console.log(   countInstances('ababa', 'aba')   ); // ==> 2
console.log(   countInstances('aaabbb', 'ab')   ); // ==> 1


0

조금 늦었지만 다음 문자열이 있다고 가정합니다.

var temp = "This is a string.";

먼저 일치시키려는 항목을 분할하면 문자열 배열이 반환됩니다.

var array = temp.split("is");

그런 다음 split은 기본적으로 크기가 1 인 배열로 정렬되므로 길이를 구하여 1을 뺍니다. 결과적으로 발생을 찾을 때마다 크기가 증가합니다.

var occurrenceCount = array.length - 1;
alert(occurrenceCount); //should output '2'

다음과 같이이 모든 작업을 한 줄로 수행 할 수도 있습니다.

alert("This is a string.".split("is").length - 1); //should output '2'

그것이 도움이되기를 바랍니다 : D


1
이것을 중복 답변으로 표시 할 수 있습니까? 자신의 답변을 제공하기 전에 모든 답변을 읽어야합니까?
Michiel

2
이 @Orbit 's의 대답 ... 나중에 8 년
codidact.com로 이동 aloisdg

1
이 응답을 삭제해야합니까?
Juan Enrique Segebre

0

이 솔루션은 .replace()RegEx를 첫 번째 매개 변수로 사용 하는 방법과 함수를 두 번째 매개 변수로 사용하여 카운터를 증가시키는 클로저로 사용할 수 있습니다 ...

/**
 * Return the frequency of a substring in a string
 * @param {string} string - The string.
 * @param {string} string - The substring to count.
 * @returns {number} number - The frequency.
 * 
 * @author Drozerah https://gist.github.com/Drozerah/2b8e08d28413d66c3e63d7fce80994ce
 * @see https://stackoverflow.com/a/55670859/9370788
 */
const subStringCounter = (string, subString) => {

    let count = 0
    string.replace(new RegExp(subString, 'gi'), () => count++)
    return count
}

용법

subStringCounter("foofoofoo", "bar"); //0

subStringCounter("foofoofoo", "foo"); //3

0

이 게시물을 발견했습니다.

let str = 'As sly as a fox, as strong as an ox';

let target = 'as'; // let's look for it

let pos = 0;
while (true) {
  let foundPos = str.indexOf(target, pos);
  if (foundPos == -1) break;

  alert( `Found at ${foundPos}` );
  pos = foundPos + 1; // continue the search from the next position
}

동일한 알고리즘을 더 짧게 배치 할 수 있습니다.

let str = "As sly as a fox, as strong as an ox";
let target = "as";

let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
  alert( pos );
}

0

substr_count PHP에서 Javascript로 번역


function substr_count (haystack, needle, offset, length) { 
  // eslint-disable-line camelcase
  //  discuss at: https://locutus.io/php/substr_count/
  // original by: Kevin van Zonneveld (https://kvz.io)
  // bugfixed by: Onno Marsman (https://twitter.com/onnomarsman)
  // improved by: Brett Zamir (https://brett-zamir.me)
  // improved by: Thomas
  //   example 1: substr_count('Kevin van Zonneveld', 'e')
  //   returns 1: 3
  //   example 2: substr_count('Kevin van Zonneveld', 'K', 1)
  //   returns 2: 0
  //   example 3: substr_count('Kevin van Zonneveld', 'Z', 0, 10)
  //   returns 3: false

  var cnt = 0

  haystack += ''
  needle += ''
  if (isNaN(offset)) {
    offset = 0
  }
  if (isNaN(length)) {
    length = 0
  }
  if (needle.length === 0) {
    return false
  }
  offset--

  while ((offset = haystack.indexOf(needle, offset + 1)) !== -1) {
    if (length > 0 && (offset + needle.length) > length) {
      return false
    }
    cnt++
  }

  return cnt
}

Locutus의 Php의 substr_count 함수 변환을 확인하십시오.


-2

이 시도:

function countString(str, search){
    var count=0;
    var index=str.indexOf(search);
    while(index!=-1){
        count++;
        index=str.indexOf(search,index+1);
    }
    return count;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.