Java: Antall ord forekomst i streng

Kilde node: 1719850

Introduksjon

Å telle antall ordforekomster i en streng er en ganske enkel oppgave, men har flere måter å gjøre det på. Du må også ta hensyn til effektiviteten til metoden, siden du vanligvis vil bruke automatiserte verktøy når du ikke ønsker å utføre manuelt arbeid – dvs. når søkeområdet er stort.

I denne veiledningen lærer du hvordan du teller antall ordforekomster i en streng i Java:

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

Vi vil søke etter antall forekomster av targetWord, Ved hjelp String.split(), Collections.frequency() og regulære uttrykk.

Tell ordforekomster i streng med String.split ()

Den enkleste måten å telle forekomsten av et målord i en streng er å dele strengen på hvert ord, og iterere gjennom matrisen, økende en wordCount på hver kamp. Merk at når et ord har noen form for tegnsetting rundt seg, for eksempel wants. på slutten av setningen – den enkle ord-nivådelingen vil behandle riktig wants og wants. som separate ord!

For å omgå dette kan du enkelt fjerne all tegnsetting fra setningen før du dele det opp:

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

for løkke, itererer vi ganske enkelt gjennom matrisen, og sjekker om elementet ved hver indeks er lik targetWord. Hvis det er det, øker vi wordCount, som på slutten av utførelsen, skriver ut:

2

Tell ordforekomster i streng med Collections.frequency()

De Collections.frequency() metoden gir en mye renere implementering på høyere nivå, som abstraherer bort en enkel for loop, og sjekker for både identitet (om et objekt is et annet objekt) og likhet (om et objekt er likt med et annet objekt, avhengig av de kvalitative egenskapene til det objektet).

De frequency() metoden aksepterer en liste å søke gjennom, og målobjektet, og fungerer for alle andre objekter også, der atferden avhenger av hvordan objektet selv implementerer equals(). Når det gjelder strenger, equals() sjekker for innholdet i strengen:


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

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

Her har vi konvertert matrisen hentet fra split() inn i en Java ArrayList, ved hjelp av hjelperen asList() metode av Arrays klasse. Reduksjonsoperasjonen frequency() returnerer et heltall som angir frekvensen av targetWord i listen, og resulterer i:

2

Ordforekomster i streng med Matcher (regulære uttrykk – RegEx)

Til slutt kan du bruke regulære uttrykk til å søke etter mønstre og telle antall samsvarende mønstre. Regular Expressions er laget for dette, så det passer veldig naturlig for oppgaven. I Java er Pattern klasse brukes til å representere og kompilere regulære uttrykk, og Matcher klasse brukes til å finne og matche mønstre.

Ved å bruke RegEx kan vi kode tegnsettingsinvariansen inn i selve uttrykket, så det er ikke nødvendig å formatere strengen eksternt eller fjerne tegnsetting, noe som er å foretrekke for store tekster der det kan være kostbart å lagre en annen endret versjon i minnet:

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

Dette resulterer også i:

2

Benchmark for effektivitet

Så, hvilken er den mest effektive? La oss kjøre en liten 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));

Hver metode vil bli kjørt 100000 XNUMX ganger (jo høyere tall, jo lavere varians og resultater på grunn av tilfeldigheter, på grunn av loven om store tall). Å kjøre denne koden resulterer i:

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

Men – hva skjer hvis vi gjør søket mer beregningsmessig kostbart ved å gjøre det større? La oss generere en syntetisk setning:

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

Dette lager en streng med innholdet:

hello world hello world hello world hello ...

Sjekk ut vår praktiske, praktiske guide for å lære Git, med beste praksis, bransjeaksepterte standarder og inkludert jukseark. Slutt å google Git-kommandoer og faktisk lære den!

Nå, hvis vi skulle søke etter enten "hei" eller "verden" - ville det vært mange flere treff enn de to fra før. Hvordan fungerer metodene våre nå i benchmark?

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

Nå kommer array splitting raskest ut! Generelt avhenger benchmarks av ulike faktorer – for eksempel søkeområdet, målordet osv. og din personlige brukssituasjon kan være forskjellig fra benchmarken.

Råd: Prøv metodene på din egen tekst, noter tidene og velg den mest effektive og elegante for deg.

konklusjonen

I denne korte veiledningen har vi tatt en titt på hvordan man teller ordforekomster for et målord, i en streng i Java. Vi har startet med å dele opp strengen og bruke en enkel teller, etterfulgt av å bruke Collections hjelperklasse, og til slutt ved å bruke regulære uttrykk.

Til slutt har vi benchmarket metodene og lagt merke til at ytelsen ikke er lineær, og avhenger av søkeområdet. For lengre inndatatekster med mange treff, ser det ut til å dele arrays å være den mest effektive. Prøv alle tre metodene på egen hånd, og velg den mest effektive.

Tidstempel:

Mer fra Stackabuse