문자열에서 하위 문자열의 발생


122

다음 알고리즘이 중단되지 않는 이유는 무엇입니까? (str은 내가 검색하는 문자열이고, findStr은 내가 찾으려는 문자열입니다)

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while (lastIndex != -1) {
    lastIndex = str.indexOf(findStr,lastIndex);

    if( lastIndex != -1)
        count++;

    lastIndex += findStr.length();
}

System.out.println(count);

8
우리는 Udacity에서 정말 좋은 일을했습니다. newSTR = str.replace (findStr, ""); 그리고 반환 된 count = ((str.length ()-newSTR.length ()) / findStr.length ());
SolarLunix

캐릭터에 대한 유사한 질문 : stackoverflow.com/q/275944/873282
koppor

검색 문자열의 접두사가 접미사 인 경우도 고려하고 싶지 않습니까? 이 경우 제안 된 답변 중 어느 것도 작동하지 않을 것이라고 생각합니다. 여기 에 예가 있습니다. 이 경우 CLRS 책에 코딩 된 Knuth Morris Pratt (KMP)와 같은보다 정교한 알고리즘이 필요합니다
Sid

'중지'조건 (lastIndex == -1)에 도달 한 후 lastIndex (lastIndex + = findStr.length ();)의 값을 증가시켜 재설정하기 때문에 중지되지 않습니다.
Legna

답변:


83

마지막 줄은 문제를 일으켰습니다. lastIndex-1이 아니므로 무한 루프가 있습니다. 코드의 마지막 줄을 if 블록으로 이동하여이 문제를 해결할 수 있습니다.

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while(lastIndex != -1){

    lastIndex = str.indexOf(findStr,lastIndex);

    if(lastIndex != -1){
        count ++;
        lastIndex += findStr.length();
    }
}
System.out.println(count);

121
이 답장은 내가 한 시간 전에 작성한 게시물의 정확한 사본입니다.)
Olivier

8
예상 한 결과를 반환 할 수도 있고 반환하지 않을 수도 있습니다. 하위 문자열 "aa"및 검색 문자열 "aaa"를 사용하여 예상되는 발생 횟수는 1 (이 코드에서 반환 됨)이 될 수 있지만 2도 될 수 있습니다 (이 경우 "lastIndex + = 대신"lastIndex ++ "가 필요합니다. 찾는 항목에 따라 findStr.length () ").
Stanislav Kniazev

@olivier는 그것을 보지 못했습니다 ... :( @stan 절대적으로 맞습니다 ... 저는 문제의 코드를 수정하고있었습니다 ... bobcom이 문자열의 발생 횟수에 따라 의미하는 바에 따라 달라집니다 ...
codebreach

1
사람들은 언제 이와 같은 것을 복사하여 붙여 넣기 정적 메서드로 래핑하는 방법을 배우게 될까요? 아래 내 대답을 참조하십시오.
mmm

1
여기서 교훈은 답변을 작성하려는 경우 다른 사람이 이미 똑같은 답변을 작성했는지 여부를 먼저 확인 하는 것입니다. 답변이 복사되었는지 또는 독립적으로 작성되었는지에 관계없이 동일한 답변이 두 번 표시되는 것은 실제로 아무런 이점이 없습니다.
Dawood ibn Kareem

192

Apache Commons Lang에서 StringUtils.countMatches 를 사용하는 것은 어떻 습니까?

String str = "helloslkhellodjladfjhello";
String findStr = "hello";

System.out.println(StringUtils.countMatches(str, findStr));

그 결과 :

3

9
이 OP의 질문에 대답하지 않는 한이 제안이 얼마나 잘 상관없이, 그것은 솔루션으로 인정 될 수 없다
kommradHomer

3
이되지 않습니다 또는 뭔가 ... 내 IDE가 인식하지 못합니다
Vamsi 파반 마헤

@VamsiPavanMahesh StringUtils는 Apache Commons의 라이브러리입니다. 여기에서 확인하십시오 : commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/…
Anup

이 답변은 하루 전 Peter Lawrey의 답변의 사본입니다 (아래 참조).
Zon

StringUtilscountMatches방법 이 없습니다 .
plaidshirt

117

귀하가 lastIndex += findStr.length();어떤 선두로부터이 발견되지 때 무한 루프 (원인, 괄호 외부에 배치 된, lastIndex 속성은 항상 있었다findStr.length() ).

다음은 고정 버전입니다.

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while (lastIndex != -1) {

    lastIndex = str.indexOf(findStr, lastIndex);

    if (lastIndex != -1) {
        count++;
        lastIndex += findStr.length();
    }
}
System.out.println(count);

92

더 짧은 버전. ;)

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
System.out.println(str.split(findStr, -1).length-1);

8
return haystack.split(Pattern.quote(needle), -1).length - 1;예를 들어 경우needle=":)"
Mr_and_Mrs_D

2
@lOranger 없으면 ,-1후행 일치를 삭제합니다.
Peter Lawrey 2012

3
아야, 감사합니다. 이것은 javadoc의 작은 줄을 읽는 법을 가르쳐 줄 것입니다 ...
Laurent Grégoire

4
좋은! 하지만 겹치지 않는 일치 만 포함합니다. 예를 들어 "aaa"에서 "aa"를 일치 시키면 2가 아닌 1이 반환됩니까? 물론 겹치거나 겹치지 않는 일치를 포함하는 것은 모두 유효하며 사용자 요구 사항에 따라 달라집니다 (아마도 개수 중복을 나타내는 플래그, 예 / 아니요)?
Cornel Masson

2
-1 .. 시도 "AAAA"와 "AA"에서이 작업을 실행 .. 정답은 없습니다 2. 3
Kalyanaraman Santhanam

79

당신은 정말 스스로 매칭을 처리해야합니까? 특히 필요한 것이 발생 횟수뿐이라면 정규식이 더 깔끔합니다.

String str = "helloslkhellodjladfjhello";
Pattern p = Pattern.compile("hello");
Matcher m = p.matcher(str);
int count = 0;
while (m.find()){
    count +=1;
}
System.out.println(count);     

1
이것은 특수 문자를 찾지 않고 아래 문자열에 대해 0 카운트를 찾습니다. String str = "hel+loslkhel+lodjladfjhel+lo"; Pattern p = Pattern.compile("hel+lo");
Ben

13
예, 정규식을 올바르게 표현하면됩니다. 함께 시도 로그인합니다 정규식과 요구에 특별한 의미가 탈출해야합니다. Pattern.compile("hel\\+lo");+
Jean

4
당신이 찾고있는 것이 임의의 문자열을 가져 와서 모든 특수 정규 표현식 문자가 무시 된 정확한 일치로 사용하는 것이라면 Pattern.quote(str)친구입니다!
Mike Furtak 2015 년

2
str = "aaaaaa"일 때 "aaa"에서는 작동하지 않습니다. 이 네 대답은하지만 당신은이주는
Pujan 스리 바스타에게

이 솔루션은이 경우에 작동하지 않습니다. str = "이것은 테스트 \\ n \\ r 문자열입니다", subStr = "\\ r", 0 번 발생을 표시합니다.
Maksym Ovsianikov

19

아무도이 라이너를 언급하지 않았다는 것이 매우 놀랍습니다. 간단하고 간결하며str.split(target, -1).length-1

public static int count(String str, String target) {
    return (str.length() - str.replace(target, "").length()) / target.length();
}

최고의 답변이어야합니다. 감사합니다!
lakam99

12

여기에 멋지고 재사용 가능한 방법으로 싸여 있습니다.

public static int count(String text, String find) {
        int index = 0, count = 0, length = find.length();
        while( (index = text.indexOf(find, index)) != -1 ) {                
                index += length; count++;
        }
        return count;
}

8
String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while((lastIndex = str.indexOf(findStr, lastIndex)) != -1) {
     count++;
     lastIndex += findStr.length() - 1;
}
System.out.println(count);

루프의 끝은 3이고; 도움이되기를 바랍니다


5
코드에 오류가 있습니다. 단일 문자를 검색 findStr.length() - 1하면는 0을 반환하고 무한 순환에 있습니다.
Jan Bodnar 2014 년

6

주어진 답변 중 상당수가 다음 중 하나 이상에서 실패합니다.

  • 임의 길이의 패턴
  • 겹치는 일치 (예 : "23232"의 "232"또는 "aaa"의 "aa")
  • 정규식 메타 문자

내가 쓴 내용은 다음과 같습니다.

static int countMatches(Pattern pattern, String string)
{
    Matcher matcher = pattern.matcher(string);

    int count = 0;
    int pos = 0;
    while (matcher.find(pos))
    {
        count++;
        pos = matcher.start() + 1;
    }

    return count;
}

통화 예 :

Pattern pattern = Pattern.compile("232");
int count = countMatches(pattern, "23232"); // Returns 2

비정규 표현식 검색을 원하면 LITERAL플래그를 사용하여 패턴을 적절하게 컴파일하십시오 .

Pattern pattern = Pattern.compile("1+1", Pattern.LITERAL);
int count = countMatches(pattern, "1+1+1"); // Returns 2

예 ... Apache StringUtils에 이와 같은 것이 없다는 것에 놀랐습니다.
마이크 설치류

6
public int countOfOccurrences(String str, String subStr) {
  return (str.length() - str.replaceAll(Pattern.quote(subStr), "").length()) / subStr.length();
}

좋은 대답입니다. 어떻게 작동하는지에 대한 메모를 추가해 주시겠습니까?
santhosh kumar

물론 str-소스 문자열이고 subStr-하위 문자열입니다. 목표는 str에서 subStr의 발생량을 계산하는 것입니다. 이를 위해 다음 공식을 사용합니다. . 그래서 기본적으로 우리는 모든 subStr이없는 str의 길이 인 str의 길이에서 추출한 다음 subStr의 길이로 결과를 나눕니다. 다른 질문이 있으면 알려주세요.
Maksym Ovsianikov

Santhosh, 천만에요! 중요한 부분은 subStr에 Pattern.quote를 사용하는 것입니다. 그렇지 않으면 다음과 같은 경우에 실패 할 수 있습니다. str = "This is a test \\ n \\ r string", subStr = "\\ r". 여기에 제공된 유사한 답변 중 일부는 Pattern을 사용하지 않으므로 이러한 경우 실패합니다.
Maksym Ovsianikov

정규식에 대한 이유가 replace없습니다 replaceAll.
NateS

3

lastIndex다음 발생을 찾을 때마다 증가 합니다.

그렇지 않으면 항상 첫 번째 부분 문자열 (위치 0)을 찾습니다.


3
public int indexOf(int ch,
                   int fromIndex)

지정된 인덱스에서 검색을 시작하여 지정된 문자가 처음 나타나는이 문자열 내의 인덱스를 반환합니다.

따라서 귀하의 lastindex값은 항상 0이고 항상 문자열에서 hello 를 찾습니다 .


2

정답으로 주어진 대답은 줄 바꿈과 같은 것을 계산하는 데 좋지 않으며 너무 장황합니다. 나중에 대답하는 것이 더 좋지만 모든 것은 간단하게 얻을 수 있습니다.

str.split(findStr).length

질문의 예를 사용하여 후행 일치를 삭제하지 않습니다.


1
이것은 이미 다른 답변 에서 다루었습니다 . 그 대답도 더 좋았습니다.
michaelb958--GoFundMonica

1
이것은 다른 답변이 아닌 문제의 답변에 대한 주석이어야합니다.
james.garriss 2014 년

2

내장 라이브러리 기능을 사용하여 발생 횟수를 지정할 수 있습니다.

import org.springframework.util.StringUtils;
StringUtils.countOccurrencesOf(result, "R-")

1
작동하지 않는 경우 사용한 종속성을 지정해야합니다.
Saikat

1

lastIndex+=findStr.length()루프의 끝에 추가 하십시오. 그렇지 않으면 하위 문자열을 찾으면 동일한 마지막 위치에서 반복해서 찾으려고하기 때문에 무한 루프가됩니다.


1

이거 한번 해봐. 모든 일치 항목을 -.

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int numberOfMatches = 0;
while (str.contains(findStr)){
    str = str.replaceFirst(findStr, "-");
    numberOfMatches++;
}

파괴하고 싶지 않다면 str동일한 내용으로 새 문자열을 만들 수 있습니다.

String str = "helloslkhellodjladfjhello";
String strDestroy = str;
String findStr = "hello";
int numberOfMatches = 0;
while (strDestroy.contains(findStr)){
    strDestroy = strDestroy.replaceFirst(findStr, "-");
    numberOfMatches++;
}

이 블록을 실행하면 다음 값이됩니다.

str = "helloslkhellodjladfjhello"
strDestroy = "-slk-djladfj-"
findStr = "hello"
numberOfMatches = 3

1

@Mr_and_Mrs_D가 제안했듯이 :

String haystack = "hellolovelyworld";
String needle = "lo";
return haystack.split(Pattern.quote(needle), -1).length - 1;

1

기존 답변을 기반으로 if없이 "짧은"버전을 추가하고 싶습니다.

String str = "helloslkhellodjladfjhello";
String findStr = "hello";

int count = 0, lastIndex = 0;
while((lastIndex = str.indexOf(findStr, lastIndex)) != -1) {
    lastIndex += findStr.length() - 1;
    count++;
}

System.out.println(count); // output: 3

이것은 문자열이 반복되는지, 예를 들어 문자열 'xxx'에서 문자열 'xx'를 찾는 경우를 고려합니다.
tCoe

1

다음은 사용자가 입력 한 문자열에서 토큰이 발생한 횟수를 계산하는 고급 버전입니다.

public class StringIndexOf {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        System.out.println("Enter a sentence please: \n");
        String string = scanner.nextLine();

        int atIndex = 0;
        int count = 0;

        while (atIndex != -1)
        {
            atIndex = string.indexOf("hello", atIndex);

            if(atIndex != -1)
            {
                count++;
                atIndex += 5;
            }
        }

        System.out.println(count);
    }

}

1

아래 방법은 전체 문자열에서 하위 문자열이 몇 번 반복되는지 보여줍니다. 희망 전체 사용 :-

    String searchPattern="aaa"; // search string
    String str="aaaaaababaaaaaa"; // whole string
    int searchLength = searchPattern.length(); 
    int totalLength = str.length(); 
    int k = 0;
    for (int i = 0; i < totalLength - searchLength + 1; i++) {
        String subStr = str.substring(i, searchLength + i);
        if (subStr.equals(searchPattern)) {
           k++;
        }

    }

0

regexp / patterns / matchers를 사용하지 않거나 StringUtils를 사용하지 않는 다른 솔루션이 있습니다.

String str = "helloslkhellodjladfjhelloarunkumarhelloasdhelloaruhelloasrhello";
        String findStr = "hello";
        int count =0;
        int findStrLength = findStr.length();
        for(int i=0;i<str.length();i++){
            if(findStr.startsWith(Character.toString(str.charAt(i)))){
                if(str.substring(i).length() >= findStrLength){
                    if(str.substring(i, i+findStrLength).equals(findStr)){
                        count++;
                    }
                }
            }
        }
        System.out.println(count);

0

원래 문자열 내에서 각 하위 문자열의 인덱스가 필요한 경우 다음과 같이 indexOf로 작업을 수행 할 수 있습니다.

 private static List<Integer> getAllIndexesOfSubstringInString(String fullString, String substring) {
    int pointIndex = 0;
    List<Integer> allOccurences = new ArrayList<Integer>();
    while(fullPdfText.indexOf(substring,pointIndex) >= 0){
       allOccurences.add(fullPdfText.indexOf(substring, pointIndex));
       pointIndex = fullPdfText.indexOf(substring, pointIndex) + substring.length();
    }
    return allOccurences;
}

0
public static int getCountSubString(String str , String sub){
int n = 0, m = 0, counter = 0, counterSub = 0;
while(n < str.length()){
  counter = 0;
  m = 0;
  while(m < sub.length() && str.charAt(n) == sub.charAt(m)){
    counter++;
    m++; n++;
  }
  if (counter == sub.length()){
    counterSub++;
    continue;
  }
  else if(counter > 0){
    continue;
  }
  n++;
}

return  counterSub;

}


이 문제는 8 세이며,이 게시 22 개 다른 솔루션보다 더 나은 솔루션 이유의 표시없이, 그것은 아마 제거되어야합니다
제이슨 휠러

0

이 솔루션은 문자열 전체에 주어진 하위 문자열의 총 발생 수를 인쇄하고 중복 일치가 존재하는 경우도 포함합니다.

class SubstringMatch{
    public static void main(String []args){
        //String str = "aaaaabaabdcaa";
        //String sub = "aa";
        //String str = "caaab";
        //String sub = "aa";
        String str="abababababaabb";
        String sub = "bab";

        int n = str.length();
        int m = sub.length();

        // index=-1 in case of no match, otherwise >=0(first match position)
        int index=str.indexOf(sub), i=index+1, count=(index>=0)?1:0;
        System.out.println(i+" "+index+" "+count);

        // i will traverse up to only (m-n) position
        while(index!=-1 && i<=(n-m)){   
            index=str.substring(i, n).indexOf(sub);
            count=(index>=0)?count+1:count;
            i=i+index+1;  
            System.out.println(i+" "+index);
        }
        System.out.println("count: "+count);
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.