Java: numărați numărul de apariții de cuvinte în șir

Introducere

Numărarea numărului de apariții de cuvinte dintr-un șir este o sarcină destul de ușoară, dar are mai multe abordări pentru a face acest lucru. Trebuie să țineți cont și de eficiența metodei, deoarece veți dori de obicei să utilizați instrumente automate atunci când nu doriți să efectuați muncă manuală - adică atunci când spațiul de căutare este mare.

În acest ghid, veți învăța cum să numărați numărul de apariții ale cuvintelor dintr-un șir în Java:

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

Vom căuta numărul de apariții ale targetWord, Folosind String.split(), Collections.frequency() și expresii regulate.

Numărați aparițiile cuvintelor din șir cu String.split()

Cel mai simplu mod de a număra apariția unui cuvânt țintă într-un șir este de a împărți șirul pe fiecare cuvânt și de a itera prin matrice, incrementând un wordCount la fiecare meci. Rețineți că atunci când un cuvânt are orice fel de punctuație în jurul său, cum ar fi wants. la sfârșitul propoziției – împărțirea simplă la nivel de cuvânt va trata corect wants și wants. ca cuvinte separate!

Pentru a rezolva acest lucru, puteți elimina cu ușurință toate semnele de punctuație din propoziție înainte împărțirea lui:

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

În for buclă, pur și simplu iterăm prin matrice, verificând dacă elementul de la fiecare index este egal cu targetWord. Dacă este, creștem valoarea wordCount, care la sfârșitul execuției, tipărește:

2

Numărați aparițiile cuvintelor din șir cu Collections.frequency()

Collections.frequency() Metoda oferă o implementare mult mai curată, de nivel superior, care face abstractie de un simplu for buclă și verifică atât identitatea (dacă un obiect is alt obiect) și egalitate (dacă un obiect este egal cu un alt obiect, în funcție de trăsăturile calitative ale acelui obiect).

frequency() metoda acceptă o listă prin care să căutați și obiectul țintă și funcționează și pentru toate celelalte obiecte, unde comportamentul depinde de modul în care obiectul însuși implementează equals(). În cazul șirurilor, equals() verificări pentru conținutul șirului:


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

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

Aici, am convertit matricea obținută din split() într-un Java ArrayList, folosind ajutorul asList() metodă a Arrays clasă. Operația de reducere frequency() returnează un număr întreg care denotă frecvența lui targetWord în listă și are ca rezultat:

2

Apariții de cuvinte în șir cu Potrivire (Expresii regulate – RegEx)

În cele din urmă, puteți utiliza expresii regulate pentru a căuta modele și pentru a număra numărul de modele potrivite. Expresiile regulate sunt făcute pentru aceasta, așa că este o potrivire foarte naturală pentru sarcină. În Java, Pattern clasa este folosită pentru a reprezenta și a compila expresii regulate și Matcher clasa este folosită pentru a găsi și potrivi modele.

Folosind RegEx, putem codifica invarianța punctuației în expresia însăși, astfel încât nu este nevoie să formatăm extern șirul sau să eliminați semnele de punctuație, ceea ce este de preferat pentru textele mari în care stocarea unei alte versiuni modificate în memorie ar putea fi costisitoare:

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

Acest lucru are ca rezultat și:

2

Benchmark de eficiență

Deci, care este cel mai eficient? Să rulăm un mic benchmark:

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

Fiecare metodă va fi rulată de 100000 de ori (cu cât numărul este mai mare, cu atât varianța și rezultatele datorate întâmplării sunt mai mici, datorită legii numerelor mari). Rularea acestui cod are ca rezultat:

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

Totuși – ce se întâmplă dacă facem căutarea mai costisitoare din punct de vedere computațional, făcând-o mai mare? Să generăm o propoziție sintetică:

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

Aceasta creează un șir cu conținutul:

hello world hello world hello world hello ...

Consultați ghidul nostru practic și practic pentru a învăța Git, cu cele mai bune practici, standarde acceptate de industrie și fisa de cheat incluse. Opriți căutarea pe Google a comenzilor Git și de fapt învăţa aceasta!

Acum, dacă ar fi să căutăm fie „bună ziua”, fie „lume” – ar fi mult mai multe potriviri decât cele două de înainte. Cum se descurcă metodele noastre acum în benchmark?

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

Acum, împărțirea matricei iese cel mai rapid! În general, benchmark-urile depind de diverși factori – cum ar fi spațiul de căutare, cuvântul țintă etc. și cazul dvs. personal de utilizare ar putea fi diferit de benchmark.

Indicații: Încearcă metodele pe propriul text, notează orele și alege-o pe cea mai eficientă și elegantă pentru tine.

Concluzie

În acest scurt ghid, am analizat cum să numărăm aparițiile unui cuvânt pentru un cuvânt țintă, într-un șir în Java. Am început prin a împărți șirul și a folosi un contor simplu, urmat de a folosi Collections clasa de ajutor și, în sfârșit, folosind expresii regulate.

În cele din urmă, am evaluat metodele și am observat că performanța nu este liniară și depinde de spațiul de căutare. Pentru textele de intrare mai lungi cu multe potriviri, împărțirea matricelor pare a fi cea mai performantă. Încercați toate cele trei metode pe cont propriu și alegeți-o pe cea mai performantă.

Timestamp-ul:

Mai mult de la Stackabuse