Sự xuất hiện của chuỗi con trong một chuỗi


122

Tại sao thuật toán sau không tạm dừng đối với tôi? (str là chuỗi tôi đang tìm kiếm, findStr là chuỗi tôi đang cố gắng tìm)

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
Chúng tôi đã làm một điều thực sự tốt trong Udacity: chúng tôi sử dụng newSTR = str.replace (findStr, ""); và trả về count = ((str.length () - newSTR.length ()) / findStr.length ());
SolarLunix

Câu hỏi tương tự cho các nhân vật: stackoverflow.com/q/275944/873282
koppor

Bạn cũng không muốn tính đến trường hợp tiền tố của chuỗi tìm kiếm là hậu tố của nó sao? Trong trường hợp đó, tôi không nghĩ rằng bất kỳ câu trả lời được đề xuất nào sẽ hiệu quả. đây là một ví dụ. Trong trường hợp đó, bạn sẽ cần một thuật toán phức tạp hơn, như Knuth Morris Pratt (KMP) được mã hóa trong sách CLRS
Sid

nó không được ngăn chặn cho bạn, bởi vì sau khi đạt trạng thái 'dừng lại' của bạn (lastIndex == -1), bạn thiết lập lại nó bằng cách tăng giá trị của lastIndex (lastIndex + = findStr.length ();)
Legna

Câu trả lời:


83

Dòng cuối cùng đang tạo ra một vấn đề. lastIndexsẽ không bao giờ ở -1, vì vậy sẽ có một vòng lặp vô hạn. Điều này có thể được khắc phục bằng cách chuyển dòng mã cuối cùng vào khối 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
Câu trả lời này là bản sao chính xác của bài đăng mà tôi đã thực hiện một giờ trước đó;)
Olivier

8
Lưu ý rằng điều này có thể có hoặc không trả lại kết quả mong đợi. Với chuỗi con "aa" và chuỗi để tìm kiếm "aaa", số lần xuất hiện dự kiến ​​có thể là một (do mã này trả về), nhưng cũng có thể là hai (trong trường hợp này, bạn sẽ cần "lastIndex ++" thay vì "lastIndex + = findStr.length () ") tùy thuộc vào những gì bạn đang tìm kiếm.
Stanislav Kniazev

@olivier không thấy điều đó ... :( @stan điều đó hoàn toàn chính xác ... tôi chỉ đang sửa mã trong sự cố ... đoán nó phụ thuộc vào ý nghĩa của bobcom theo số lần xuất hiện trong chuỗi ...
codebreach

1
Khi nào mọi người sẽ học cách bọc những thứ như thế này trong một phương pháp sao chép và dán tĩnh? Xem câu trả lời của tôi bên dưới, nó cũng được tối ưu hóa hơn.
mmm,

1
Đạo đức ở đây là nếu bạn định viết câu trả lời, trước tiên hãy kiểm tra xem người khác đã viết câu trả lời chính xác hay chưa. Thực sự không có lợi gì khi cùng một câu trả lời xuất hiện hai lần, bất kể câu trả lời của bạn được sao chép hay được viết độc lập.
Dawood ibn Kareem,

192

Làm thế nào về việc sử dụng StringUtils.countMatches từ Apache Commons Lang?

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

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

Kết quả đầu ra:

3

9
Không có vấn đề như thế nào đúng đề nghị này là, nó không thể được chấp nhận như là một giải pháp vì nó không được trả lời câu hỏi OP của
kommradHomer

3
Đây có phải là bị phản đối hoặc một cái gì đó .. IDE của tôi không nhận ra
Vamsi Pavan Mahesh

@VamsiPavanMahesh StringUtils là một thư viện của Apache Commons. Kiểm tra tại đây: commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/…
Anup

Câu trả lời này là bản sao câu trả lời của Peter Lawrey một ngày trước đó (xem bên dưới).
Zon

StringUtilskhông có countMatchesphương pháp.
plaidshirt

117

Của bạn lastIndex += findStr.length();được đặt bên ngoài dấu ngoặc, gây ra một vòng lặp vô hạn (khi không tìm thấy sự xuất hiện nào, lastIndex luôn làfindStr.length() ).

Đây là phiên bản cố định:

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

Một phiên bản ngắn hơn. ;)

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;nếu chẳng hạnneedle=":)"
Mr_and_Mrs_D

2
@lOranger Nếu không có ,-1nó sẽ giảm các kết quả phù hợp.
Peter Lawrey

3
Ouch, cảm ơn, tốt để biết! Điều này sẽ dạy cho tôi để đọc các dòng nhỏ trong javadoc ...
Laurent Grégoire

4
Đẹp! Nhưng nó chỉ bao gồm các trận đấu không trùng lặp, phải không? Ví dụ: kết hợp "aa" trong "aaa" sẽ trả về 1, không phải 2? Tất nhiên bao gồm cả các kết quả trùng lặp hoặc không trùng lặp đều hợp lệ và phụ thuộc vào yêu cầu của người dùng (có lẽ là một lá cờ để chỉ ra số lượng trùng lặp, có / không)?
Cornel Masson

2
-1 .. thử chạy này trên "aaaa" và "aa" .. câu trả lời đúng là 3 không 2.
Kalyanaraman Santhanam

79

Bạn có thực sự phải tự mình xử lý kết hợp không? Đặc biệt nếu tất cả những gì bạn cần là số lần xuất hiện, thì biểu thức chính quy sẽ gọn hơn:

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
Điều này KHÔNG tìm thấy các ký tự đặc biệt, nó sẽ tìm thấy số 0 cho các chuỗi bên dưới: String str = "hel+loslkhel+lodjladfjhel+lo"; Pattern p = Pattern.compile("hel+lo");
Ben

13
có nó sẽ xảy ra nếu bạn thể hiện regex của mình một cách chính xác. thử với Pattern.compile("hel\\+lo");các +dấu hiệu có một ý nghĩa đặc biệt trong một regex và nhu cầu để được thoát.
Jean

4
Nếu những gì bạn đang tìm kiếm là lấy một Chuỗi tùy ý và sử dụng nó làm đối sánh chính xác với tất cả các ký tự biểu thức chính quy đặc biệt bị bỏ qua, đó Pattern.quote(str)là bạn của bạn!
Mike Furtak

2
điều này không hoạt động đối với "aaa" khi str = "aaaaaa". Có 4 câu trả lời nhưng bạn đưa ra 2
Pujan Srivastava

Giải pháp này không hoạt động cho trường hợp này: str = "Đây là một chuỗi thử nghiệm \\ n \\ r", subStr = "\\ r", nó hiển thị 0 lần xuất hiện.
Maksym Ovsianikov

19

Tôi rất ngạc nhiên là không ai đề cập đến cái lót này. Nó đơn giản, ngắn gọn và hoạt động tốt hơn một chút so vớistr.split(target, -1).length-1

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

Nên là câu trả lời hàng đầu. Cảm ơn bạn!
lakam99,

12

Nó đây, được gói gọn trong một phương pháp hay và có thể tái sử dụng:

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

ở cuối vòng lặp số đếm là 3; hy vọng nó giúp


5
Mã có lỗi. Nếu chúng ta tìm kiếm một ký tự duy nhất, giá trị findStr.length() - 1trả về là 0 và chúng ta đang ở trong một chu kỳ vô tận.
Jan Bodnar

6

Rất nhiều câu trả lời được đưa ra không thành công với một hoặc nhiều:

  • Các mẫu có độ dài tùy ý
  • Các kết quả trùng lặp (chẳng hạn như đếm "232" trong "23232" hoặc "aa" trong "aaa")
  • Ký tự meta biểu thức chính quy

Đây là những gì tôi đã viết:

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

Cuộc gọi ví dụ:

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

Nếu bạn muốn tìm kiếm không phải cụm từ thông dụng, chỉ cần biên dịch mẫu của bạn một cách thích hợp với LITERALcờ:

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

Vâng ... ngạc nhiên là không có thứ gì như thế này trong Apache StringUtils.
mike Rodent

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

Câu trả lời tốt. Bạn có thể vui lòng thêm một số ghi chú về cách nó hoạt động?
santhosh kumar

Chắc chắn, str - là chuỗi nguồn của chúng ta, subStr - là một chuỗi con. Mục đích là để tính toán số lần xuất hiện của subStr trong str. Để làm điều này, chúng tôi sử dụng công thức: (ab) / c, trong đó a - độ dài của str, b - độ dài của str mà không có tất cả các lần xuất hiện của subStr (chúng tôi xóa tất cả các lần xuất hiện của subStr khỏi str cho điều này), c - độ dài của subStr . Vì vậy, về cơ bản chúng ta trích xuất từ ​​độ dài của str - độ dài của str mà không có tất cả các subStr, và sau đó chúng ta chia kết quả cho độ dài của subStr. Vui lòng cho tôi biết nếu bạn có bất kỳ câu hỏi nào khác.
Maksym Ovsianikov

Santhosh, bạn được chào đón! Phần quan trọng là sử dụng Pattern.quote cho subStr, nếu không trong một số trường hợp có thể bị lỗi, như trường hợp này: str = "Đây là một thử nghiệm \\ n \\ r string", subStr = "\\ r". Một số câu trả lời tương tự được cung cấp ở đây không sử dụng Pattern, vì vậy chúng sẽ không thành công trong những trường hợp như vậy.
Maksym Ovsianikov

Không có lý do cho regex, sử dụng replace, không replaceAll.
NateS

3

Sự gia tăng lastIndexbất cứ khi nào bạn tìm kiếm sự xuất hiện tiếp theo.

Nếu không, nó luôn tìm thấy chuỗi con đầu tiên (ở vị trí 0).


3
public int indexOf(int ch,
                   int fromIndex)

Trả về chỉ mục trong chuỗi này của lần xuất hiện đầu tiên của ký tự được chỉ định, bắt đầu tìm kiếm tại chỉ mục được chỉ định.

Vì vậy, lastindexgiá trị của bạn luôn là 0 và nó luôn tìm thấy hello trong chuỗi.


2

Câu trả lời được đưa ra là đúng sẽ không tốt cho việc đếm những thứ như trả về dòng và quá dài dòng. Câu trả lời sau này tốt hơn nhưng tất cả đều có thể đạt được đơn giản với

str.split(findStr).length

Nó không bỏ các kết quả phù hợp theo sau bằng cách sử dụng ví dụ trong câu hỏi.


1
Điều này đã được đề cập trong một câu trả lời khác rồi; và câu trả lời đó cũng đã làm tốt hơn.
michaelb958 - GoFundMonica

1
Đây phải là một nhận xét về câu trả lời được đề cập, không phải là một câu trả lời khác.
james.garriss

2

Bạn có thể đánh số lần xuất hiện bằng cách sử dụng hàm thư viện có sẵn:

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

1
Không hoạt động, bạn nên chỉ định phụ thuộc bạn đã sử dụng.
Saikat

1

hãy thử thêm lastIndex+=findStr.length()vào cuối vòng lặp của bạn, nếu không bạn sẽ kết thúc trong một vòng lặp vô tận vì một khi bạn tìm thấy chuỗi con, bạn đang cố gắng tìm lại nó từ cùng một vị trí cuối cùng.


1

Hãy thử cái này. Nó thay thế tất cả các trận đấu bằng a -.

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

Và nếu bạn không muốn phá hủy của strbạn, bạn có thể tạo một chuỗi mới có cùng nội dung:

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

Sau khi thực hiện khối này, đây sẽ là các giá trị của bạn:

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

1

Như @Mr_and_Mrs_D đã đề xuất:

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

1

Dựa trên (các) câu trả lời hiện có, tôi muốn thêm phiên bản "ngắn hơn" mà không có 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

điều này sẽ tính đến nếu chuỗi lặp lại, ví dụ: nếu bạn đang tìm kiếm chuỗi 'xx' trong chuỗi 'xxx'.
tCoe

1

Đây là phiên bản nâng cao để đếm số lần mã thông báo xảy ra trong một chuỗi do người dùng nhập:

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

Phương thức dưới đây cho biết số lần lặp lại chuỗi con trên toàn bộ chuỗi của bạn. Hy vọng sử dụng đầy đủ cho bạn: -

    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

đây là giải pháp khác mà không cần sử dụng regexp / pattern / matchers hoặc thậm chí không sử dụng 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

Nếu bạn cần chỉ mục của từng chuỗi con trong chuỗi ban đầu, bạn có thể thực hiện điều gì đó với indexOf như sau:

 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;

}


câu hỏi này là 8 tuổi, và không có bất kỳ dấu hiệu về việc tại sao đây là một giải pháp tốt hơn so với 22 giải pháp khác được đăng, nó có lẽ nên được gỡ bỏ
Jason Wheeler

0

Giải pháp này in ra tổng số lần xuất hiện của một chuỗi con nhất định trong suốt chuỗi, cũng bao gồm các trường hợp có các kết quả trùng lặp tồn tại.

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);
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.