Bir dizede alt dize oluşumu


122

Aşağıdaki algoritma neden benim için durmuyor? (str, aradığım dizedir, findStr, bulmaya çalıştığım dizedir)

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'de gerçekten iyi bir iş çıkardık: newSTR = str.replace (findStr, "") kullandık; ve sayı = ((str.length () - newSTR.length ()) / findStr.length ());
SolarLunix

Karakterler için benzer soru: stackoverflow.com/q/275944/873282
koppor

Arama dizesinin ön ekinin son ek olduğu durumu da hesaba katmak istemez misiniz? Bu durumda önerilen cevapların hiçbirinin işe yarayacağını düşünmüyorum. işte bir örnek. Bu durumda, CLRS kitabında kodlanan Knuth Morris Pratt (KMP) gibi daha ayrıntılı bir algoritmaya ihtiyacınız olacaktır
Sid

sizin için durmuyor, çünkü 'durma' koşulunuza (lastIndex == -1) ulaştıktan sonra lastIndex'in değerini artırarak sıfırlarsınız (lastIndex + = findStr.length ();)
Legna

Yanıtlar:


83

Son satır bir sorun yaratıyordu. lastIndexasla -1'de olmaz, bu yüzden sonsuz bir döngü olur. Bu, kodun son satırını if bloğuna taşıyarak düzeltilebilir.

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
Bu cevap, bir saat önce yaptığım gönderinin tam kopyası;)
Olivier

8
Bunun beklenen sonucu döndürebileceğini veya dönmeyebileceğini unutmayın. "Aa" alt dizesi ve "aaa" araması için dize ile beklenen oluşum sayısı bir olabilir (bu kod tarafından döndürülür), ancak iki de olabilir (bu durumda "lastIndex + = yerine" lastIndex ++ "gerekir findStr.length () ") aradığınıza göre değişir.
Stanislav Kniazev

@olivier bunu görmedi ... :( @ ve bu kesinlikle doğru ... ben sadece problemdeki kodu düzeltiyordum ... tahmin et bobcom'un dizedeki oluşum sayısına göre ne anlama geldiğine bağlı ...
codebreach

1
İnsanlar böyle şeyleri bir kopyalayıp statik yöntemle yapıştırmayı ne zaman öğrenecekler? Aşağıdaki cevabıma bakın, ayrıca daha optimize edilmiş.
mmm

1
Buradaki ahlaki, bir cevap yazmak istiyorsanız, önce başka birinin tam olarak aynı cevabı yazıp yazmadığını kontrol edin . Cevabınızın kopyalanması veya bağımsız olarak yazılması fark etmeksizin, aynı cevabın iki kez görünmesinin gerçekten bir faydası yoktur.
Dawood ibn Kareem

192

Apache Commons Lang'den StringUtils.countMatches kullanmaya ne dersiniz ?

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

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

Bu çıktı:

3

9
Bu öneri ne kadar doğru olursa olsun, OP'nin sorusunu cevaplamadığı için çözüm olarak kabul edilemez
kommradHomer

3
Bu kullanımdan kaldırıldı mı yoksa başka bir şey mi ..
IDE'm

@VamsiPavanMahesh StringUtils, Apache Commons'ın bir kütüphanesidir. Burayı kontrol edin: commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/…
Anup

Bu cevap, Peter Lawrey'nin bir gün önceki cevabının bir kopyasıdır (aşağıya bakınız).
Bölge

StringUtils değil sahiptir countMatches yöntem.
plaidshirt

117

Sizin lastIndex += findStr.length(); sonsuz döngüye neden parantez dışına yerleştirilmiştir (no oluşumu tespit edildi lastIndex hep oldu findStr.length()).

İşte sabit versiyon:

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

Daha kısa bir versiyon. ;)

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;örneğinneedle=":)"
Mr_and_Mrs_D

2
@Oranger olmadan ,-1takip eden maçlar düşecektir.
Peter Lawrey

3
Ah, teşekkürler, bilmek güzel! Bu bana javadoc'taki küçük satırları okumayı öğretecek ...
Laurent Grégoire

4
Güzel! Ama sadece çakışmayan eşleşmeleri içeriyor, değil mi? Örneğin, "aaa" da "aa" ile eşleşmek 2 değil 1 döndürür? Elbette örtüşen veya örtüşmeyen eşleşmeleri dahil etmek hem geçerlidir hem de kullanıcı gereksinimlerine bağlıdır (belki de sayım çakışmalarını gösteren bir işaret, evet / hayır)?
Cornel Masson

2
-1 .. bunu "aaaa" ve "aa" üzerinde çalıştırmayı deneyin .. doğru cevap 3 değil 2'dir.
Kalyanaraman Santhanam

79

Eşleştirmeyi gerçekten kendin halletmek zorunda mısın? Özellikle ihtiyacınız olan tek şey gerçekleşme sayısı ise, normal ifadeler daha derli topludur:

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
Bu özel karakterler String str = "hel+loslkhel+lodjladfjhel+lo"; Pattern p = Pattern.compile("hel+lo");
Ben

13
evet, normal ifadenizi doğru bir şekilde ifade ederseniz olur. ile denemek işareti bir regex ve ihtiyaçları özel bir anlam kaçan gerekir. Pattern.compile("hel\\+lo");+
Jean

4
Eğer aradığınız şey, rastgele bir String alıp, onu tüm özel normal ifade karakterleri göz ardı edilen tam bir eşleşme olarak kullanmaksa Pattern.quote(str), arkadaşınız!
Mike Furtak

2
str = "aaaaaa" olduğunda bu "aaa" için çalışmaz. 4 cevap var ama sizinki 2 veriyor
Pujan Srivastava

Bu çözüm bu durumda çalışmaz: str = "Bu bir test \\ n \\ r dizesidir", subStr = "\\ r", 0 oluşum gösterir.
Maksym Ovsianikov 01

19

Kimsenin bundan bahsetmemesine çok şaşırdım. Basit, özlü ve performansından biraz daha iyistr.split(target, -1).length-1

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

En iyi cevap olmalı. Teşekkür ederim!
lakam99

12

İşte güzel ve tekrar kullanılabilir bir yöntemle özetlenmiş:

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

döngü sonunda 3'tür; Umarım yardımcı olur


5
Kod bir hata içeriyor. Tek bir karakter findStr.length() - 1ararsak 0 ile döner ve sonsuz bir döngüdeyiz.
Jan Bodnar

6

Verilen cevapların çoğu şunlardan birinde veya daha fazlasında başarısız oluyor:

  • Keyfi uzunluk kalıpları
  • Çakışan eşleşmeler ("23232" de "232" veya "aaa" da "aa" sayma gibi)
  • Normal ifade meta karakterleri

İşte yazdıklarım:

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

Örnek çağrı:

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

Normal olmayan bir arama istiyorsanız, kalıbınızı uygun bir şekilde LITERALbayrakla derleyin :

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

Evet ... Apache StringUtils'te böyle bir şeyin olmamasına şaşırdım.
mike kemirgen

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

İyi cevap. Nasıl çalıştığına dair bazı notlar eklemenin bir sakıncası var mı?
santhosh kumar

Elbette, str - bizim kaynak dizemiz, subStr - bir alt dizedir. Amaç, str'deki subStr oluşumlarının miktarını hesaplamaktır. Bunu yapmak için, şu formülü kullanıyoruz: (ab) / c, burada a - str uzunluğu, b - str uzunluğu, tüm subStr oluşumları olmadan (bunun için tüm subStr oluşumlarını str'den kaldırıyoruz), c - subStr uzunluğu . Bu nedenle, temel olarak tüm subStr olmadan str uzunluğunun str uzunluğundan çıkarırız ve sonra sonucu subStr uzunluğuna böleriz. Başka sorunuz varsa lütfen bize bildirin.
Maksym Ovsianikov

Santhosh, rica ederim! Önemli kısım, subStr için Pattern.quote kullanmaktır, aksi takdirde in, bunun gibi bazı durumlarda başarısız olabilir: str = "Bu bir test \\ n \\ r dizesidir", subStr = "\\ r". Burada verilen bazı benzer yanıtlar Kalıp kullanmaz, bu nedenle bu gibi durumlarda başarısız olurlar.
Maksym Ovsianikov

Normal ifade için bir neden yok, kullanın replace, değil replaceAll.
NateS

3

Artış lastIndexsonraki geçtiği için bak ne zaman.

Aksi takdirde, her zaman ilk alt dizeyi bulur (0 konumunda).


3
public int indexOf(int ch,
                   int fromIndex)

Aramayı belirtilen dizinde başlatarak, belirtilen karakterin ilk oluşumunun bu dizge içindeki dizini döndürür.

Yani lastindexdeğeriniz her zaman 0'dır ve dizede her zaman merhaba bulur .


2

Doğru olarak verilen cevap, satır dönüşleri gibi şeyleri saymak için iyi değildir ve fazlasıyla ayrıntılıdır. Daha sonra cevaplar daha iyidir, ancak hepsi basit bir şekilde elde edilebilir

str.split(findStr).length

Sorudaki örneği kullanarak takip eden eşleşmeleri düşürmez.


1
Bu zaten başka bir cevapta ele alındı; ve bu cevap da daha iyi yaptı.
michaelb958 - GoFundMonica

1
Bu, başka bir cevap değil, söz konusu cevap için bir yorum olmalıdır.
james.garriss

2

Dahili kütüphane işlevini kullanarak oluşumların sayısını yapabilirsiniz:

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

1
Çalışmıyor, kullandığınız bağımlılığı belirtmelisiniz.
Saikat

1

Döngünüzün lastIndex+=findStr.length()sonuna eklemeyi deneyin , aksi takdirde sonsuz bir döngüye girersiniz çünkü alt dizeyi bulduğunuzda, aynı son konumdan tekrar tekrar bulmaya çalışıyorsunuzdur.


1

Bunu dene. Tüm eşleşmeleri bir -.

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

Ve kendinizi yok etmek istemiyorsanız str, aynı içeriğe sahip yeni bir dize oluşturabilirsiniz:

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

Bu bloğu yürüttükten sonra bunlar sizin değerleriniz olacaktır:

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

1

@Mr_and_Mrs_D'nin önerdiği gibi:

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

1

Mevcut yanıtlara dayanarak, şu koşulsuz "daha kısa" bir versiyon eklemek istiyorum:

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

bu, örneğin bir 'xxx' dizesinde 'xx' dizesini arıyorsanız, dizenin tekrar etmesi durumunda hesaba katılır.
tCoe

1

Kullanıcı tarafından girilen bir dizede jetonun kaç kez oluştuğunu saymak için gelişmiş sürüm:

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

Aşağıdaki yöntem, dizenin tamamında alt dizenin kaç kez yinelendiğini gösterir. Umarım tam size göre: -

    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

burada regexp / pattern / matchers kullanmadan veya StringUtils kullanmadan diğer çözüm.

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

Orijinal dizedeki her bir alt dizenin dizinine ihtiyacınız varsa, indexOf ile şu şekilde bir şeyler yapabilirsiniz:

 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;

}


bu soru 8 yaşında ve bunun neden yayınlanan diğer 22 çözümden daha iyi bir çözüm olduğuna dair herhangi bir gösterge olmadan muhtemelen kaldırılması gerekiyor
Jason Wheeler

0

Bu çözüm, dizgi boyunca belirli bir alt dizenin toplam oluşum sayısını yazdırır, ayrıca çakışan eşleşmelerin olduğu durumları da içerir.

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);
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.