Terjadinya substring dalam sebuah string

122

Mengapa algoritme berikut tidak berhenti untuk saya? (str adalah string yang saya cari, findStr adalah string yang saya coba temukan)

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);
Robert Harvey
sumber
8
Kami melakukan yang sangat bagus di Udacity: kami menggunakan newSTR = str.replace (findStr, ""); dan mengembalikan count = ((str.length () - newSTR.length ()) / findStr.length ());
SolarLunix
Pertanyaan serupa untuk karakter: stackoverflow.com/q/275944/873282
koppor
Tidakkah Anda juga ingin menjelaskan kasus di mana awalan string pencarian adalah sufiksnya? Dalam hal ini, menurut saya jawaban yang disarankan tidak akan berhasil. berikut ini contohnya. Dalam hal ini, Anda memerlukan algoritme yang lebih rumit, seperti Knuth Morris Pratt (KMP) yang dikodekan dalam buku CLRS
Sid
itu tidak berhenti untuk Anda, karena setelah mencapai kondisi 'halt' Anda (lastIndex == -1) Anda mengatur ulang dengan menaikkan nilai lastIndex (lastIndex + = findStr.length ();)
Legna

Jawaban:

83

Baris terakhir membuat masalah. lastIndextidak akan pernah berada di -1, jadi akan ada loop tak terbatas. Ini dapat diperbaiki dengan memindahkan baris kode terakhir ke blok 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);
codebreach
sumber
121
Balasan ini adalah salinan persis dari kiriman yang saya buat satu jam sebelumnya;)
Olivier
8
Perhatikan bahwa ini mungkin atau mungkin tidak mengembalikan hasil yang diharapkan. Dengan substring "aa" dan string untuk mencari "aaa", jumlah kemunculan yang diharapkan mungkin satu (dikembalikan oleh kode ini), tetapi mungkin juga dua (dalam hal ini Anda memerlukan "lastIndex ++" daripada "lastIndex + = findStr.length () ") tergantung pada apa yang Anda cari.
Stanislav Kniazev
@olivier tidak melihat bahwa ... :( @stan itu benar-benar benar ... saya baru saja memperbaiki kode dalam masalah ... tebak itu tergantung pada apa yang dimaksud bobcom dengan jumlah kemunculan dalam string ...
codebreach
1
Kapan orang akan belajar membungkus hal-hal seperti ini dalam metode statis salin dan tempel? Lihat jawaban saya di bawah, ini juga lebih dioptimalkan.
mmm
1
Moral di sini adalah jika Anda berniat menulis jawaban, periksa dulu apakah orang lain sudah menulis jawaban yang persis sama atau belum. Tidak ada manfaatnya jika jawaban yang sama muncul dua kali, terlepas dari apakah jawaban Anda disalin, atau ditulis secara terpisah.
Dawood ibn Kareem
192

Bagaimana kalau menggunakan StringUtils.countMatches dari Apache Commons Lang?

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

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

Output itu:

3
SAYA
sumber
9
Betapapun benarnya saran ini, tidak dapat diterima sebagai solusi karena tidak menjawab pertanyaan OP
kommradHomer
3
Apakah ini usang atau semacamnya .. IDE saya tidak mengenali
Vamsi Pavan Mahesh
@VamsiPavanMahesh StringUtils adalah pustaka Apache Commons. Periksa di sini: commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/…
Anup
Jawaban ini adalah salinan dari jawaban Peter Lawrey sehari sebelumnya (lihat di bawah).
Zon
StringUtilsbelum countMatchesmetode.
kemeja kotak
117

Anda lastIndex += findStr.length();ditempatkan di luar tanda kurung, menyebabkan pengulangan tak terbatas (ketika tidak ada kemunculan yang ditemukan, lastIndex selalu ke findStr.length()).

Ini adalah versi tetapnya:

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);
Olivier
sumber
92

Versi yang lebih pendek. ;)

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
System.out.println(str.split(findStr, -1).length-1);
Peter Lawrey
sumber
8
return haystack.split(Pattern.quote(needle), -1).length - 1;jika misalnyaneedle=":)"
Mr_and_Mrs_D
2
@lOranger Tanpa ,-1itu akan menjatuhkan jejak pertandingan.
Peter Lawrey
3
Aduh, terima kasih, senang mengetahuinya! Ini akan mengajari saya untuk membaca baris-baris kecil di javadoc ...
Laurent Grégoire
4
Bagus! Tapi itu hanya mencakup pertandingan yang tidak tumpang tindih, bukan? Misalnya mencocokkan "aa" dalam "aaa" akan menghasilkan 1, bukan 2? Tentu saja memasukkan kecocokan yang tumpang tindih atau tidak tumpang tindih keduanya valid dan bergantung pada kebutuhan pengguna (mungkin tanda untuk menunjukkan jumlah tumpang tindih, ya / tidak)?
Cornel Masson
2
-1 .. coba jalankan ini di "aaaa" dan "aa" .. jawaban yang benar adalah 3 bukan 2.
Kalyanaraman Santhanam
79

Apakah Anda benar-benar harus menangani pencocokan sendiri? Terutama jika yang Anda butuhkan hanyalah jumlah kemunculan, ekspresi reguler lebih rapi:

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);     
Jean
sumber
1
Ini TIDAK menemukan karakter khusus, ia akan menemukan 0 hitungan untuk string di bawah ini: String str = "hel+loslkhel+lodjladfjhel+lo"; Pattern p = Pattern.compile("hel+lo");
Ben
13
ya itu akan terjadi jika Anda mengekspresikan ekspresi reguler dengan benar. cobalah dengan Pattern.compile("hel\\+lo");yang +tanda memiliki arti khusus dalam regex dan kebutuhan untuk melarikan diri.
Jean
4
Jika yang Anda cari adalah mengambil String yang berubah-ubah dan menggunakannya sebagai pencocokan persis dengan semua karakter ekspresi reguler yang diabaikan, Pattern.quote(str)itu teman Anda!
Mike Furtak
2
ini tidak bekerja untuk "aaa" saat str = "aaaaaa". Ada 4 jawaban tetapi jawaban Anda 2
Pujan Srivastava
Solusi ini tidak berfungsi untuk kasus ini: str = "This is a test \\ n \\ r string", subStr = "\\ r", ini menunjukkan 0 kejadian.
Maksym Ovsianikov
19

Saya sangat terkejut tidak ada yang menyebutkan liner yang satu ini. Sederhana, ringkas, dan berkinerja sedikit lebih baik daripadastr.split(target, -1).length-1

public static int count(String str, String target) {
    return (str.length() - str.replace(target, "").length()) / target.length();
}
kmecpp
sumber
Harus menjadi jawaban teratas. Terima kasih!
lakam99
12

Ini dia, dibungkus dengan metode yang bagus dan dapat digunakan kembali:

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;
}
mmm
sumber
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);

di akhir hitungan loop adalah 3; semoga membantu

dfa
sumber
5
Kode mengandung kesalahan. Jika kita mencari satu karakter, findStr.length() - 1hasilnya 0 dan kita berada dalam siklus tanpa akhir.
Jan Bodnar
6

Banyak jawaban yang diberikan gagal pada satu atau lebih dari:

  • Pola dengan panjang sembarang
  • Kecocokan yang tumpang tindih (seperti menghitung "232" dalam "23232" atau "aa" dalam "aaa")
  • Karakter meta ekspresi reguler

Inilah yang saya tulis:

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

Contoh panggilan:

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

Jika Anda menginginkan pencarian non-regular-expression, cukup kompilasi pola Anda secara tepat dengan LITERALflag:

Pattern pattern = Pattern.compile("1+1", Pattern.LITERAL);
int count = countMatches(pattern, "1+1+1"); // Returns 2
benkc
sumber
Ya ... terkejut tidak ada yang seperti ini di Apache StringUtils.
mike rodent
6
public int countOfOccurrences(String str, String subStr) {
  return (str.length() - str.replaceAll(Pattern.quote(subStr), "").length()) / subStr.length();
}
Maksym Ovsianikov
sumber
Jawaban yang bagus. Bisakah Anda menambahkan beberapa catatan tentang cara kerjanya?
santhosh kumar
Tentu, str - adalah string sumber kami, subStr - adalah substring. Tujuannya adalah untuk menghitung jumlah kemunculan subStr di str. Untuk melakukan ini, kami menggunakan rumus: (ab) / c, di mana a - panjang str, b - panjang str tanpa semua kemunculan subStr (kami menghapus semua kemunculan subStr dari str untuk ini), c - panjang subStr . Jadi pada dasarnya kita mengekstrak dari panjang str - panjang str tanpa semua subStr, lalu kita bagi hasilnya pada panjang subStr. Beri tahu saya jika Anda memiliki pertanyaan lain.
Maksym Ovsianikov
Santhosh, sama-sama! Bagian yang penting adalah menggunakan Pattern.quote untuk subStr, jika tidak dalam beberapa kasus mungkin gagal, seperti ini: str = "This is a test \\ n \\ r string", subStr = "\\ r". Beberapa jawaban serupa yang diberikan di sini tidak menggunakan Pola, jadi mereka akan gagal dalam kasus seperti itu.
Maksym Ovsianikov
Tidak ada alasan untuk regex, gunakan replace, bukan replaceAll.
NateS
3

Kenaikan lastIndexsetiap kali Anda mencari kejadian berikutnya.

Jika tidak, selalu menemukan substring pertama (pada posisi 0).

Stanislav Kniazev
sumber
3
public int indexOf(int ch,
                   int fromIndex)

Mengembalikan indeks dalam string ini dari kemunculan pertama dari karakter yang ditentukan, memulai pencarian pada indeks yang ditentukan.

Jadi lastindexnilai Anda selalu 0 dan selalu menemukan hello dalam string.

Bhushan Bhangale
sumber
2

Jawaban yang diberikan sebagai benar tidak baik untuk menghitung hal-hal seperti pengembalian baris dan terlalu bertele-tele. Jawaban selanjutnya lebih baik tetapi semua bisa dicapai hanya dengan

str.split(findStr).length

Itu tidak menjatuhkan kecocokan trailing menggunakan contoh dalam pertanyaan.

Menandai
sumber
1
Ini telah dibahas dalam jawaban lain ; dan jawaban itu juga lebih baik.
michaelb958 - GoFundMonica
1
Ini harus berupa komentar atas jawaban yang dimaksud, bukan jawaban lain.
james.garriss
2

Anda dapat jumlah kejadian menggunakan fungsi perpustakaan bawaan:

import org.springframework.util.StringUtils;
StringUtils.countOccurrencesOf(result, "R-")
Pemenang
sumber
1
Tidak berfungsi, Anda harus menentukan ketergantungan yang Anda gunakan.
Saikat
1

coba tambahkan lastIndex+=findStr.length()ke akhir loop Anda, jika tidak, Anda akan berakhir dalam loop tanpa akhir karena setelah Anda menemukan substring, Anda mencoba menemukannya berulang kali dari posisi terakhir yang sama.

Thorsten Schleinzer
sumber
1

Coba yang ini. Ini menggantikan semua pertandingan dengan a -.

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

Dan jika Anda tidak ingin menghancurkan Anda, strAnda dapat membuat string baru dengan konten yang sama:

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

Setelah menjalankan blok ini, ini akan menjadi nilai Anda:

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

Seperti yang disarankan @Mr_and_Mrs_D:

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

Berdasarkan jawaban yang ada, saya ingin menambahkan versi "lebih pendek" tanpa 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
sjkm
sumber
yang satu ini memperhitungkan jika string berulang, misalnya jika Anda mencari string 'xx' dalam string 'xxx'.
tCoe
1

Berikut adalah versi lanjutan untuk menghitung berapa kali token terjadi dalam string yang dimasukkan pengguna:

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

}
Venzentx
sumber
1

Metode di bawah ini menunjukkan berapa banyak waktu pengulangan substring pada seluruh string Anda. Semoga bermanfaat bagi Anda: -

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

    }
duggu
sumber
0

berikut adalah solusi lain tanpa menggunakan regexp / patterns / matchers atau bahkan tidak menggunakan 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);
Arun Kumar Mudraboyina
sumber
0

Jika Anda membutuhkan indeks setiap substring dalam string asli, Anda dapat melakukan sesuatu dengan indexOf seperti ini:

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

}

Nikolai Nechai
sumber
pertanyaan ini sudah berusia 8 tahun, dan tanpa indikasi mengapa ini adalah solusi yang lebih baik daripada 22 solusi lain yang diposting, pertanyaan itu mungkin harus dihapus
Jason Wheeler
0

Solusi ini mencetak jumlah total kemunculan substring tertentu di seluruh string, juga mencakup kasus di mana terdapat kecocokan yang tumpang tindih.

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);
    }
}
Anubhav Singh
sumber