Menggunakan indexOf untuk Mencari Semua Kejadian Kata dalam Rentetan

1. Gambaran keseluruhan

Kerja mencari corak watak, atau kata, dalam rentetan teks yang lebih besar dilakukan di berbagai bidang. Sebagai contoh, dalam bioinformatik, kita mungkin perlu mencari potongan DNA dalam kromosom.

Di media, editor mencari frasa tertentu dalam teks yang banyak. Pengawasan data mengesan penipuan atau spam dengan mencari kata-kata mencurigakan yang tersemat dalam data.

Dalam konteks apa pun, pencarian itu sangat terkenal dan menakutkan sehingga ia sering disebut "Jarum dalam Masalah Haystack" . Dalam tutorial ini, kami akan menunjukkan algoritma sederhana yang menggunakan kaedah indexOf (String str, int fromIndex) dari kelas Java String untuk mencari semua kejadian perkataan dalam rentetan.

2. Algoritma Mudah

Daripada hanya menghitung kejadian perkataan dalam teks yang lebih besar, algoritma kami akan mencari dan mengenal pasti setiap lokasi di mana terdapat perkataan tertentu dalam teks. Pendekatan kami untuk masalah ini pendek dan sederhana sehingga:

  1. Pencarian akan menemui perkataan itu walaupun dalam kata-kata dalam teks . Oleh itu, jika kita mencari perkataan "mampu" maka kita akan mendapatkannya dalam "selesa" dan "tablet".
  2. Pencarian akan tidak peka huruf besar kecil .
  3. Algoritma berdasarkan pendekatan carian rentetan naif . Ini bermaksud bahawa kerana kita naif tentang sifat watak dalam kata dan rentetan teks, kita akan menggunakan kekuatan kasar untuk memeriksa setiap lokasi teks untuk contoh kata pencarian.

2.1. Pelaksanaan

Sekarang setelah kami menentukan parameter untuk carian kami, mari tulis penyelesaian mudah:

public class WordIndexer { public List findWord(String textString, String word) { List indexes = new ArrayList(); String lowerCaseTextString = textString.toLowerCase(); String lowerCaseWord = word.toLowerCase(); int index = 0; while(index != -1){ index = lowerCaseTextString.indexOf(lowerCaseWord, index); if (index != -1) { indexes.add(index); index++; } } return indexes; } }

2.2. Menguji Penyelesaiannya

Untuk menguji algoritma kami, kami akan menggunakan potongan petikan terkenal dari Shakespeare's Hamlet dan mencari perkataan "atau", yang muncul lima kali:

@Test public void givenWord_whenSearching_thenFindAllIndexedLocations() { String theString; WordIndexer wordIndexer = new WordIndexer(); theString = "To be, or not to be: that is the question: " + "Whether 'tis nobler in the mind to suffer " + "The slings and arrows of outrageous fortune, " + "Or to take arms against a sea of troubles, " + "And by opposing end them? To die: to sleep; " + "No more; and by a sleep to say we end " + "The heart-ache and the thousand natural shocks " + "That flesh is heir to, 'tis a consummation " + "Devoutly to be wish'd. To die, to sleep; " + "To sleep: perchance to dream: ay, there's the rub: " + "For in that sleep of death what dreams may come,"; List expectedResult = Arrays.asList(7, 122, 130, 221, 438); List actualResult = wordIndexer.findWord(theString, "or"); assertEquals(expectedResult, actualResult); }

Semasa menjalankan ujian, kami mendapat hasil yang diharapkan. Mencari "atau" menghasilkan lima contoh yang disertakan dalam pelbagai cara dalam rentetan teks:

index of 7, in "or" index of 122, in "fortune" index of 130, in "Or index of 221, in "more" index of 438, in "For"

Dalam istilah matematik, algoritma mempunyai notasi Big-O dari O (m * (nm)) , di mana m adalah panjang perkataan dan n adalah panjang rentetan teks. Pendekatan ini mungkin sesuai untuk rentetan teks haystack dari beberapa ribu aksara tetapi akan sangat lambat jika terdapat berbilion watak.

3. Algoritma yang ditingkatkan

Contoh mudah di atas menunjukkan pendekatan yang naif dan kasar untuk mencari kata tertentu dalam rentetan teks. Oleh itu, ia akan berfungsi untuk kata carian dan teks apa pun.

Sekiranya kita mengetahui terlebih dahulu bahawa kata carian tidak mengandungi corak watak berulang, seperti "aaa", maka kita dapat menulis algoritma yang sedikit lebih efisien.

Dalam kes ini, kita dapat dengan selamat menghindari melakukan cadangan untuk memeriksa kembali setiap lokasi dalam rentetan teks sebagai lokasi permulaan yang berpotensi. Setelah kami membuat panggilan ke kaedah indexOf () , kami akan meluncur ke lokasi sejurus selepas kejadian terakhir dijumpai. Tweak sederhana ini menghasilkan senario kes terbaik dari O (n) .

Mari kita lihat versi kaedah findWord () yang lebih baik ini.

public List findWordUpgrade(String textString, String word) { List indexes = new ArrayList(); StringBuilder output = new StringBuilder(); String lowerCaseTextString = textString.toLowerCase(); String lowerCaseWord = word.toLowerCase(); int wordLength = 0; int index = 0; while(index != -1){ index = lowerCaseTextString.indexOf(lowerCaseWord, index + wordLength); // Slight improvement if (index != -1) { indexes.add(index); } wordLength = word.length(); } return indexes; }

4. Kesimpulan

Dalam tutorial ini, kami menyajikan algoritma carian tanpa huruf besar-kecil untuk mencari semua variasi kata dalam rentetan teks yang lebih besar. Tetapi jangan biarkan itu menyembunyikan fakta bahawa kaedah indexOf () kelas Java String secara semula jadi peka huruf besar kecil dan dapat membezakan antara "Bob" dan "bob", misalnya.

Secara keseluruhan, indexOf () adalah kaedah yang mudah untuk mencari urutan watak yang tersimpan dalam rentetan teks tanpa melakukan pengekodan untuk manipulasi substring.

Seperti biasa, pangkalan data lengkap contoh ini berakhir di GitHub.