Skip to content

Commit

Permalink
feat: menambahkan algoritma boyer moore (#111)
Browse files Browse the repository at this point in the history
* feat: menambahkan algoritma boyer moore

Signed-off-by: slowy07 <[email protected]>

* fix: memperbaiki over read kode

informasi kode issue:

Nama: CWE-126
Informasi: https://cwe.mitre.org/data/definitions/126.html

Signed-off-by: slowy07 <[email protected]>

---------

Signed-off-by: slowy07 <[email protected]>
  • Loading branch information
slowy07 authored Oct 13, 2024
1 parent 8a618cc commit cd0de0a
Show file tree
Hide file tree
Showing 2 changed files with 224 additions and 0 deletions.
10 changes: 10 additions & 0 deletions strings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
file(GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
foreach(testsourcefile ${APP_SOURCES})
string(REPLACE ".cpp" testname ${testsourcefile})
add_executable(${testname} ${testsourcefile})
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
if(OpenMP_CXX_FOUND)
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
endif()
install(TARGETS ${testname} DESTINATIN "bin/strings")
endforeach(testsourcefile ${APP_SOURCES})
214 changes: 214 additions & 0 deletions strings/boyer_moore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#define UKURAN_ALFABET

/**
* @namespace
* @brief Algoritma string
*/
namespace strings {
/**
* @namespace
* @brief fungsi untuk implementasi algoritma booyer-moore
*/
namespace boyer_moore {
struct pola {
// pola yang akan dicari
std::string pola_teks;
// tabel karaketer yang buruk yang digunakan heuristik karakter
// buruk pada algoritma
std::vector<size_t> karakter_buruk;
// tabel awalan baik yang digunakan dalama heuristik awalan baik
// pada algoritma boyer moore
std::vector<size_t> awalan_baik;
};

/**
* @brief fungsi untuk memproses tabel awaln baik
*
* @param teks string yang akan diproses
* @param arg tabel awalan baik yang akan diisi
* @return void
*/
void inisialisasi_awalan_baik(const std::string &teks,
std::vector<size_t> &arg) {
// resize tabel awalan baik sesuasi ukuran string
arg.resize(teks.size() + 1, 0);

std::vector<size_t> posisi_perbatasan(teks.size() + 1, 0);
// inisialisasi karakter saat ini dengan panjang string
size_t karaketer_saat_ini = teks.length();
// inisialisasi indeks perbatasan
size_t indeks_perbatasan = teks.length() + 1;
// set perbatasan terakhir
posisi_perbatasan[karaketer_saat_ini] = indeks_perbatasan;

// prosesa perbatasan untuk menemukan awalan baik
while (karaketer_saat_ini > 0) {
while (indeks_perbatasan <= teks.length() &&
teks[karaketer_saat_ini - 1] != teks[indeks_perbatasan - 1]) {
if (arg[indeks_perbatasan] == 0) {
arg[indeks_perbatasan] = indeks_perbatasan - karaketer_saat_ini;
}
indeks_perbatasan = posisi_perbatasan[indeks_perbatasan];
}

// kurangi karaketer yang sedang diperiksa
karaketer_saat_ini--;
indeks_perbatasan--;
posisi_perbatasan[karaketer_saat_ini] = indeks_perbatasan;
}

// mementukan perbatasan terbesar
size_t indeks_perbatasan_terbesar = posisi_perbatasan[0];

// isi tabel awalan baik untuk seluruh karakter
for (size_t i = 0; i < teks.size(); i++) {
if (arg[i] == 0) {
// set nilai ke perbatasan
arg[i] = indeks_perbatasan_terbesar;
}
// jika melewati perbatasan terbesar, cari perbatasan selanjutnya
if (i == indeks_perbatasan_terbesar) {
indeks_perbatasan_terbesar =
posisi_perbatasan[indeks_perbatasan_terbesar];
}
}
}

/**
* @brief fungsi untuk memproses tabel karakter buruk
*
* @param teks string yang akan diproses
* @param arg tabel karakter buruk yang akan diisi
* @return void
*/
void inisialisasi_karakter_buruk(const std::string &teks,
std::vector<size_t> &arg) {
arg.resize(teks.length());

// isi table karakter buruk dengan jarak pergeseran berdasarkan karakter
for (size_t i = 0; i < teks.length(); i++) {
// hitung jarak pergeseran untuk karakter tertentu
arg[teks[i]] = teks.length() - i - 1;
}
}

/**
* @brief fungsi untuk menginisialisasi pola
*
* @param teks yang digunakan untuk inisialisasi
* @param arg struktur pola yang diinisialisasi
* @return void
*/
void inisialisasi_pola(const std::string &teks, pola &arg) {
arg.pola_teks = teks;
inisialisasi_karakter_buruk(teks, arg.karakter_buruk);
inisialisasi_awalan_baik(teks, arg.awalan_baik);
}

/**
* @brief fungsi implementasi algoritma boyer moore
*
* @param teks teks yang akan dicari data pola
* @param arg struktur pola yang mengandung pola yang sudah di proses
* @return vektor indeks yang menyimpan kemunculan pola dalam teks
*/
std::vector<size_t> cari(const std::string &teks, const pola &arg) {
// inisialisasi posisi indeks pencarian
size_t posisi_indeks = arg.pola_teks.size() - 1;
// vektor untuk menyimpan hasil pencarian
std::vector<size_t> penyimpanan_indeks;

// lakukan pencarian
while (posisi_indeks < teks.length()) {
size_t indeks_teks = posisi_indeks;
int indeks_pola = static_cast<int>(arg.pola_teks.size()) - 1;

// badingkan pola dengan teks dari belakang
while (indeks_pola >= 0 &&
teks[indeks_teks] == arg.pola_teks[indeks_pola]) {
--indeks_pola;
--indeks_teks;
}

// jika pola cocok, save result indeks
if (indeks_pola < 0) {
penyimpanan_indeks.push_back(posisi_indeks - arg.pola_teks.length() + 1);
posisi_indeks += arg.awalan_baik[0];
} else {
posisi_indeks += std::max(arg.karakter_buruk[teks[indeks_teks]],
arg.awalan_baik[indeks_pola + 1]);
}
}

// return hasil pencarian
return penyimpanan_indeks;
}

/**
* @brief fungsi untuk memeriksa apakah pola adalah prefix dari string
*
* @param teks pointer ke beberapa bagia teks input
* @param pola pola yang sedang dicari
* @return `true` jika pola adalah prefiks dari teks
* @return `false` jika pola bukan prefiks dari teks
*/
bool adalah_prefix(const char *teks, const char *pola, size_t panjang) {
// iterasi melalui setiap karakter dari teks dan pola
for (size_t i = 0; i < panjang; i++) {
// jika mencapai akhir teks (karakter null) atau karakter tidak cocok
if (teks[i] == '\0' || teks[i] != pola[i]) {
// pola tidak cocok
return false;
}
}

// bandingkan karakter satu per satu
for (size_t i = 0; i < panjang; i++) {
if (teks[i] != pola[i]) {
// jika ada perbedaan, maka bukan prefik
return false;
}
}

// jika semua karakter cocok, pola adalah prefik
return true;
}
} // namespace boyer_moore
} // namespace strings

/**
* @brief test case untuk mencari kemunculan kata `and`
* @param teks teks yang digunakan untuk pencarian kata `and`
* @return void
*/
void uji_and(const char *teks) {
strings::boyer_moore::pola ands;
strings::boyer_moore::inisialisasi_pola("and", ands);
std::vector<size_t> indeks = strings::boyer_moore::cari(teks, ands);

assert(indeks.size() == 2);
assert(strings::boyer_moore::adalah_prefix(teks + indeks[0], "and", 3));

std::cout << "Kata 'and' ditemukan pada indeks: ";
for (size_t i : indeks) {
std::cout << i << " ";
}
std::cout << std::endl;
}

/**
* @brief fungsi utama untuk menjalankan test case
* @returns int nilai pengembalian dari status program
*/
int main() {
const char *teks_uji = "and here and there";
uji_and(teks_uji);
return 0;
}

0 comments on commit cd0de0a

Please sign in to comment.