Java: Dizedeki Kelime Oluşum Sayısını Sayma

Giriş

Bir dizgede geçen sözcük sayısını saymak oldukça kolay bir iştir, ancak bunu yapmak için çeşitli yaklaşımlar vardır. Yöntemin verimliliğini de hesaba katmanız gerekir, çünkü genellikle el işçiliği yapmak istemediğinizde, yani arama alanı geniş olduğunda, otomatikleştirilmiş araçları kullanmak isteyeceksiniz.

Bu kılavuzda, Java'da bir dizgede geçen sözcük sayısını nasıl sayacağınızı öğreneceksiniz:

String searchText = "Your body may be chrome, but the heart never changes. It wants what it wants.";
String targetWord = "wants";

Şunun tekrarlanma sayısını arayacağız: targetWordKullanılarak String.split(), Collections.frequency() ve Normal İfadeler.

İle Dizedeki Kelime Oluşumlarını Say Dize.split()

Bir dizgede bir hedef kelimenin tekrarını saymanın en basit yolu, dizgiyi her bir kelimeye bölmek ve dizi boyunca yineleyerek bir wordCount her maçta Bir kelimenin etrafında herhangi bir noktalama işareti olduğunda, örneğin wants. cümlenin sonunda - basit kelime düzeyinde bölme doğru şekilde ele alınacaktır wants ve wants. ayrı kelimeler olarak!

Bu soruna geçici bir çözüm bulmak için tüm noktalama işaretlerini cümleden kolayca kaldırabilirsiniz. önce onu bölmek:

String[] words = searchText.replaceAll("p{Punct}", "").split(" ");

int wordCount = 0;
for (int i=0; i < words.length; i++)
    if (words[i].equals(targetWord))
        wordCount++;
System.out.println(wordCount);

içinde for döngüde, her dizindeki öğenin şuna eşit olup olmadığını kontrol ederek diziyi yineleriz: targetWord. Eğer öyleyse, artırıyoruz wordCount, yürütmenin sonunda şunu yazdırır:

2

İle Dizedeki Kelime Oluşumlarını Say Koleksiyonlar.frekans()

The Collections.frequency() yöntem, basit bir soyutlamayı ortadan kaldıran çok daha temiz, daha üst düzey bir uygulama sağlar. for döngü ve her iki kimliği de kontrol eder (bir nesnenin is başka bir nesne) ve eşitlik (bir nesnenin niteliksel özelliklerine bağlı olarak bir nesnenin başka bir nesneye eşit olup olmadığı).

The frequency() yöntem, aranacak bir listeyi ve hedef nesneyi kabul eder ve davranışın nesnenin kendisinin nasıl uyguladığına bağlı olduğu diğer tüm nesneler için de çalışır. equals(). Dizeler söz konusu olduğunda, equals() için kontroller dizinin içeriği:


searchText = searchText.replaceAll("p{Punct}", "");

int wordCount = Collections.frequency(Arrays.asList(searchText.split(" ")), targetWord);
System.out.println(wordCount);

Burada, elde edilen diziyi dönüştürdük split() bir Java'ya ArrayList, yardımcıyı kullanarak asList() yöntem Arrays sınıf. küçültme işlemi frequency() sıklığını gösteren bir tamsayı döndürür targetWord listede ve şu şekilde sonuçlanır:

2

Dize ile Kelime Oluşumları Eşleştirici (Normal İfadeler – Normal İfadeler)

Son olarak, kalıpları aramak ve eşleşen kalıpların sayısını saymak için Normal İfadeleri kullanabilirsiniz. Bunun için Normal İfadeler yapılır, bu nedenle göreve çok doğal bir şekilde uyar. Java'da, Pattern class, Normal İfadeleri temsil etmek ve derlemek için kullanılır ve Matcher class kalıpları bulmak ve eşleştirmek için kullanılır.

RegEx'i kullanarak, noktalama değişmezliğini ifadenin kendisine kodlayabiliriz, bu nedenle dizeyi harici olarak biçimlendirmeye veya noktalama işaretlerini kaldırmaya gerek yoktur; bu, başka bir değiştirilmiş sürümü bellekte saklamanın pahalı olabileceği büyük metinler için tercih edilir:

Pattern pattern = Pattern.compile("b%s(?!w)".format(targetWord));

Pattern pattern = Pattern.compile("bwants(?!w)");
Matcher matcher = pattern.matcher(searchText);

int wordCount = 0;
while (matcher.find())
    wordCount++;

System.out.println(wordCount);

Bu ayrıca aşağıdakilerle de sonuçlanır:

2

Verimlilik Kıyaslaması

Peki, hangisi en verimli? Küçük bir kıyaslama yapalım:

int runs = 100000;

long start1 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithSplit(searchText, targetWord);
}

long end1 = System.currentTimeMillis();
System.out.println(String.format("Array split approach took: %s miliseconds", end1-start1));

long start2 = System.currentTimeMillis();
  for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithCollections(searchText, targetWord);
}

long end2 = System.currentTimeMillis();
System.out.println(String.format("Collections.frequency() approach took: %s miliseconds", end2-start2));

long start3 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithRegex(searchText, targetWord);
}

long end3 = System.currentTimeMillis();
System.out.println(String.format("Regex approach took: %s miliseconds", end3-start3));

Her yöntem 100000 kez çalıştırılacaktır (sayı ne kadar yüksek olursa, büyük sayılar kanunu nedeniyle şansa bağlı varyans ve sonuçlar o kadar düşük olur). Bu kodu çalıştırmak şunlarla sonuçlanır:

Array split approach took: 152 miliseconds
Collections.frequency() approach took: 140 miliseconds
Regex approach took: 92 miliseconds

Bununla birlikte, aramayı daha büyük yaparak hesaplama açısından daha pahalı hale getirirsek ne olur? Sentetik bir cümle oluşturalım:

List possibleWords = Arrays.asList("hello", "world ");
StringBuffer searchTextBuffer = new StringBuffer();

for (int i = 0; i < 100; i++) {
    searchTextBuffer.append(String.join(" ", possibleWords));
}
System.out.println(searchTextBuffer);

Bu, içeriği olan bir dize oluşturur:

hello world hello world hello world hello ...

En iyi uygulamalar, endüstri tarafından kabul edilen standartlar ve dahil edilen hile sayfası ile Git'i öğrenmek için uygulamalı, pratik kılavuzumuza göz atın. Googling Git komutlarını durdurun ve aslında öğrenmek o!

Şimdi, "merhaba" veya "dünya" için arama yapacak olsaydık, önceki ikisinden çok daha fazla eşleşme olurdu. Yöntemlerimiz şimdi kıyaslamada ne yapıyor?

Array split approach took: 606 miliseconds
Collections.frequency() approach took: 899 miliseconds
Regex approach took: 801 miliseconds

Şimdi, dizi bölme en hızlı şekilde ortaya çıkıyor! Genel olarak kıyaslamalar, arama alanı, hedef kelime vb. gibi çeşitli faktörlere bağlıdır ve kişisel kullanım durumunuz kıyaslamadan farklı olabilir.

Önerileri: Yöntemleri kendi metninizde deneyin, süreleri not edin ve sizin için en verimli ve şık olanı seçin.

Sonuç

Bu kısa kılavuzda, Java'da bir dizgede bir hedef kelime için kelime oluşumlarının nasıl sayılacağına bir göz attık. Dizeyi bölerek ve basit bir sayaç kullanarak başladık, ardından Collections yardımcı sınıf ve son olarak Normal İfadeler kullanarak.

Sonunda, yöntemleri kıyasladık ve performansın doğrusal olmadığını ve arama alanına bağlı olduğunu not ettik. Birçok eşleşme içeren daha uzun giriş metinleri için, dizileri bölmek en performanslısı gibi görünüyor. Üç yöntemi de kendi başınıza deneyin ve en performanslı olanı seçin.

Zaman Damgası:

Den fazla Yığın kötüye kullanımı