Java: Sanojen lukumäärä merkkijonossa

Lähdesolmu: 1719850

esittely

Sanojen esiintymien lukumäärän laskeminen merkkijonossa on melko helppo tehtävä, mutta siinä on useita tapoja tehdä se. Menetelmän tehokkuuskin on huomioitava, sillä yleensä halutaan käyttää automatisoituja työkaluja, kun et halua tehdä manuaalista työtä – eli kun hakutila on suuri.

Tässä oppaassa opit laskemaan sanan esiintymisten lukumäärän merkkijonossa Javassa:

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

Etsimme esiintymien lukumäärää targetWord, Käyttäen String.split(), Collections.frequency() ja säännölliset lausekkeet.

Laske sanan esiintymiset merkkijonossa kanssa String.split()

Yksinkertaisin tapa laskea kohdesanan esiintyminen merkkijonossa on jakaa kunkin sanan merkkijono ja iteroida taulukon läpi lisäämällä wordCount jokaisessa ottelussa. Huomaa, että kun sanan ympärillä on jonkinlainen välimerkki, kuten wants. lauseen lopussa – yksinkertainen sanatason jako käsittelee oikein wants ja wants. erillisinä sanoina!

Voit kiertää tämän poistamalla helposti kaikki välimerkit lauseesta ennen jakaa se:

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

In for silmukan, iteroimme yksinkertaisesti taulukon läpi ja tarkistamme, onko kunkin indeksin elementti yhtä suuri kuin targetWord. Jos on, lisäämme arvoa wordCount, joka tulostaa suorituksen lopussa:

2

Laske sanan esiintymiset merkkijonossa kanssa Kokoelmat.frekvenssi()

- Collections.frequency() menetelmä tarjoaa paljon puhtaamman, korkeamman tason toteutuksen, joka abstraktioi yksinkertaisen for silmukka ja tarkistaa molempien identiteetin (oliko objekti is toinen objekti) ja tasa-arvo (onko objekti samanarvoinen toisen objektin kanssa, riippuen kyseisen objektin laadullisista ominaisuuksista).

- frequency() menetelmä hyväksyy luettelon, josta haetaan, ja kohdeobjektin ja toimii myös kaikille muille objekteille, joissa käyttäytyminen riippuu siitä, kuinka objekti itse toteuttaa equals(). merkkijonojen tapauksessa equals() tarkistaa merkkijonon sisältö:


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

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

Tässä olemme muuntaneet taulukosta saadun taulukon split() Javaksi ArrayList, käyttämällä auttajaa asList() menetelmä Arrays luokkaa. Vähennysoperaatio frequency() palauttaa kokonaisluvun, joka ilmaisee taajuuden targetWord luettelossa ja tuloksena:

2

Sana esiintyy merkkijonossa kanssa Vastaava (säännölliset lausekkeet – säännöllinen lauseke)

Lopuksi voit käyttää säännöllisiä lausekkeita etsiäksesi malleja ja laskeaksesi yhteensopivien kuvioiden määrän. Säännölliset lausekkeet on tehty tätä varten, joten se sopii hyvin luonnollisesti tehtävään. Javassa, Pattern luokkaa käytetään edustamaan ja kääntämään säännöllisiä lausekkeita, ja Matcher luokkaa käytetään kuvioiden etsimiseen ja yhdistämiseen.

RegEx:n avulla voimme koodata välimerkkien invarianssin itse lausekkeeseen, joten merkkijonoa ei tarvitse ulkoisesti muotoilla tai poistaa välimerkkejä, mikä on parempi suurille teksteille, joissa toisen muunnetun version tallentaminen muistiin saattaa olla vaarallista:

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

Tästä seuraa myös:

2

Tehokkuusvertailu

Joten mikä on tehokkain? Suoritetaan pieni 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));

Jokainen menetelmä ajetaan 100000 XNUMX kertaa (mitä suurempi luku, sitä pienempi varianssi ja tulokset johtuvat sattumasta suurten lukujen lain vuoksi). Tämän koodin suorittaminen johtaa:

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

Mutta mitä tapahtuu, jos teemme hausta laskennallisesti kalliimman tekemällä siitä suuremman? Luodaan synteettinen lause:

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

Tämä luo merkkijonon, jonka sisältö on:

hello world hello world hello world hello ...

Tutustu käytännönläheiseen, käytännölliseen Gitin oppimisoppaaseemme, jossa on parhaat käytännöt, alan hyväksymät standardit ja mukana tuleva huijauslehti. Lopeta Git-komentojen googlailu ja oikeastaan oppia se!

Jos etsisimme sanaa "hei" tai "maailma", löytyisi paljon enemmän osumia kuin kaksi aikaisempaa. Miten menetelmämme menestyvät nyt vertailussa?

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

Nyt joukon jakaminen tapahtuu nopeimmin! Yleisesti ottaen vertailuarvot riippuvat useista tekijöistä – kuten hakutilasta, kohdesanasta jne., ja henkilökohtainen käyttötapasi voi olla erilainen kuin vertailuarvo.

Neuvo: Kokeile menetelmiä omassa tekstissäsi, merkitse ajat muistiin ja valitse sinulle tehokkain ja tyylikkäin.

Yhteenveto

Tässä lyhyessä oppaassa olemme tarkastelleet, kuinka kohdesanan sanaesiintymät lasketaan Java-merkkijonossa. Aloitimme jakamalla merkkijonon ja käyttämällä yksinkertaista laskuria, jonka jälkeen käytämme Collections auttajaluokka ja lopuksi käyttämällä säännöllisiä lausekkeita.

Lopulta olemme vertailleet menetelmiä ja todenneet, että suorituskyky ei ole lineaarinen ja riippuu hakutilasta. Pidemmille syöttöteksteille, joissa on monia osumia, taulukoiden jakaminen näyttää olevan tehokkain. Kokeile kaikkia kolmea menetelmää itse ja valitse tehokkain.

Aikaleima:

Lisää aiheesta Stackabus