@sideid/id-profanity-filter 1.11.13 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +91 -129
- package/README.md +172 -447
- package/dist/index.d.ts +11 -6
- package/dist/index.esm.js +161 -180
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +161 -180
- package/dist/index.js.map +1 -1
- package/dist/types/core/matcher.d.ts +5 -5
- package/dist/types/index.d.ts +5 -0
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/utils/ahoCorasick.d.ts +10 -0
- package/eslint.config.mjs +1 -0
- package/examples/advanced.ts +4 -1
- package/examples/custom-list.ts +3 -3
- package/package.json +9 -2
- package/rollup.config.mjs +5 -1
- package/src/constants/categories/sexual.ts +1 -1
- package/src/constants/regions/general.ts +3 -3
- package/src/constants/wordList.ts +0 -27
- package/src/core/filter.ts +58 -178
- package/src/core/matcher.ts +69 -43
- package/src/index.ts +8 -0
- package/src/types/index.ts +1 -11
- package/src/utils/ahoCorasick.ts +37 -0
- package/src/utils/regexUtils.ts +1 -2
- package/src/utils/similarityUtils.ts +0 -4
- package/test/matcher.test.ts +18 -0
- package/test/profanity-filter.test.ts +15 -0
- package/.eslintrc.js +0 -44
- package/src/constants/regions/ambon.ts +0 -0
- package/src/constants/regions/banjar.ts +0 -0
- package/src/constants/regions/bugis.ts +0 -0
- package/src/constants/regions/lampung.ts +0 -0
- package/src/constants/regions/manado.ts +0 -0
- package/src/constants/regions/ntb.ts +0 -0
- package/src/constants/regions/ntt.ts +0 -0
- package/src/constants/regions/palembang.ts +0 -0
- package/src/constants/regions/papua.ts +0 -0
package/README.md
CHANGED
|
@@ -1,548 +1,273 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img alt="SideID - Profanity Filter" src="https://socialify.git.ci/SideeID/id-profanity-filter/image?custom_description=Library+JavaScript%2FTypeScript+untuk+mendeteksi%2C+menyensor%2C+dan+menganalisis+kata-kata+kotor+dalam+Indonesia+dan+daerah.&description=1&font=Inter&forks=1&language=1&name=1&owner=1&pattern=Circuit+Board&stargazers=1&theme=Auto">
|
|
3
|
+
</div>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-

|
|
5
|
-

|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<div align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/@sideid/id-profanity-filter">
|
|
9
|
+
<img src="https://img.shields.io/npm/v/@sideid/id-profanity-filter.svg" alt="NPM Version">
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://github.com/SideeID/id-profanity-filter">
|
|
12
|
+
<img src="https://img.shields.io/github/license/SideeID/id-profanity-filter" alt="GitHub License">
|
|
13
|
+
</a>
|
|
14
|
+
</div>
|
|
8
15
|
|
|
9
|
-
|
|
16
|
+
# id-profanity-filter
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
18
|
+
Library JavaScript dan TypeScript untuk mendeteksi, menyensor, dan menganalisis kata kotor dalam bahasa Indonesia serta berbagai bahasa daerah.
|
|
19
|
+
|
|
20
|
+
## Fitur
|
|
21
|
+
|
|
22
|
+
- Deteksi kata kotor dan umpatan dalam bahasa Indonesia dan dialek daerah (Jawa, Sunda, Batak, Betawi, Minang, Bali, Madura, Aceh)
|
|
23
|
+
- Sensor fleksibel: ganti karakter (`*`, `#`), grawlix acak (`#@$%&!`), sensor penuh, atau pertahankan huruf pertama dan terakhir
|
|
24
|
+
- Deteksi variasi penulisan: leetspeak (`4nj1ng`), kata terpisah (`a-n-j-i-n-g`), dan typo via Levenshtein distance
|
|
25
|
+
- Analisis teks: skor keparahan (0-1), kategorisasi, analisis per kalimat, pencarian konteks sekitar, dan batch analysis
|
|
26
|
+
- Mendukung whitelist kata dan daftar kata kustom (`wordList`)
|
|
27
|
+
- Preset siap pakai: `strict`, `moderate`, `light`, dan `childSafe`
|
|
28
|
+
- Dukungan penuh TypeScript dengan tipe data lengkap
|
|
19
29
|
|
|
20
30
|
## Instalasi
|
|
21
31
|
|
|
22
32
|
```bash
|
|
23
33
|
npm install @sideid/id-profanity-filter
|
|
24
34
|
# atau
|
|
25
|
-
|
|
35
|
+
bun add @sideid/id-profanity-filter
|
|
26
36
|
# atau
|
|
27
37
|
pnpm add @sideid/id-profanity-filter
|
|
28
38
|
```
|
|
29
39
|
|
|
30
|
-
## Penggunaan
|
|
40
|
+
## Penggunaan dasar
|
|
31
41
|
|
|
32
|
-
###
|
|
42
|
+
### Menggunakan class IDProfanityFilter
|
|
33
43
|
|
|
34
44
|
```typescript
|
|
35
45
|
import IDProfanityFilter from '@sideid/id-profanity-filter';
|
|
36
46
|
|
|
37
|
-
// Buat instance filter
|
|
38
47
|
const filter = new IDProfanityFilter();
|
|
39
|
-
|
|
40
|
-
// Cek apakah teks mengandung kata kotor
|
|
41
48
|
const teks = 'Dasar anjing kamu, jangan banyak bacot!';
|
|
42
|
-
const hasProfanity = filter.isProfane(teks);
|
|
43
|
-
|
|
44
|
-
console.log(hasProfanity); // Output: true
|
|
45
|
-
|
|
46
|
-
// Filter kata kotor (sensorisasi)
|
|
47
|
-
const hasil = filter.filter(teks);
|
|
48
|
-
console.log(hasil.filtered); // Output: "Dasar ***** kamu, jangan banyak *****!"
|
|
49
|
-
console.log(hasil.censored); // Output: 2 (jumlah kata yang disensor)
|
|
50
|
-
|
|
51
|
-
// Analisis konten
|
|
52
|
-
const analisis = filter.analyze(teks);
|
|
53
|
-
console.log(analisis.severityScore); // Output: 0.65 (contoh skor keparahan)
|
|
54
|
-
console.log(analisis.categories); // Output: ["profanity", "insult"]
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Menggunakan Preset
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
import IDProfanityFilter from '@sideid/id-profanity-filter';
|
|
61
|
-
|
|
62
|
-
// Buat instance filter dengan preset
|
|
63
|
-
const filter = new IDProfanityFilter();
|
|
64
|
-
filter.usePreset('strict');
|
|
65
|
-
|
|
66
|
-
// Atau dengan opsi tambahan
|
|
67
|
-
filter.usePreset('childSafe', {
|
|
68
|
-
replaceWith: '#',
|
|
69
|
-
useRandomGrawlix: true,
|
|
70
|
-
});
|
|
71
49
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
50
|
+
// Cek apakah teks mengandung kata kotor
|
|
51
|
+
if (filter.isProfane(teks)) {
|
|
52
|
+
// Sensor kata kotor
|
|
53
|
+
const hasil = filter.filter(teks);
|
|
54
|
+
console.log(hasil.filtered);
|
|
55
|
+
// Output: "Dasar ****** kamu, jangan banyak *****!"
|
|
56
|
+
console.log(hasil.censored);
|
|
57
|
+
// Output: 2
|
|
58
|
+
|
|
59
|
+
// Analisis detail
|
|
60
|
+
const analisis = filter.analyze(teks);
|
|
61
|
+
console.log(analisis.categories);
|
|
62
|
+
// Output: ["profanity", "insult"]
|
|
63
|
+
console.log(analisis.regions);
|
|
64
|
+
// Output: ["general", "jawa"]
|
|
65
|
+
console.log(analisis.severityScore);
|
|
66
|
+
// Output: 0.36
|
|
67
|
+
}
|
|
75
68
|
```
|
|
76
69
|
|
|
77
|
-
###
|
|
70
|
+
### Menggunakan fungsi statis (idFilter)
|
|
78
71
|
|
|
79
|
-
|
|
72
|
+
Jika tidak memerlukan konfigurasi instance khusus, gunakan helper `idFilter`:
|
|
80
73
|
|
|
81
74
|
```typescript
|
|
82
75
|
import { idFilter } from '@sideid/id-profanity-filter';
|
|
83
76
|
|
|
84
77
|
const teks = 'Dasar anjing kamu, jangan banyak bacot!';
|
|
78
|
+
|
|
79
|
+
// Filter langsung
|
|
85
80
|
const hasil = idFilter.filter(teks);
|
|
86
|
-
console.log(hasil.filtered);
|
|
81
|
+
console.log(hasil.filtered);
|
|
87
82
|
|
|
88
|
-
//
|
|
89
|
-
|
|
90
|
-
teks,
|
|
91
|
-
idFilter.getPresetOptions('moderate'),
|
|
92
|
-
);
|
|
83
|
+
// Cek cepat
|
|
84
|
+
console.log(idFilter.isProfane(teks)); // true
|
|
93
85
|
```
|
|
94
86
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
### Kelas `IDProfanityFilter`
|
|
98
|
-
|
|
99
|
-
#### Konstruktor
|
|
87
|
+
### Menggunakan preset
|
|
100
88
|
|
|
101
89
|
```typescript
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
- **options**: Opsi konfigurasi filter (opsional)
|
|
106
|
-
|
|
107
|
-
#### Metode
|
|
108
|
-
|
|
109
|
-
##### `filter(text: string): FilterResult`
|
|
110
|
-
|
|
111
|
-
Menyensor kata kotor dalam teks.
|
|
112
|
-
|
|
113
|
-
- **Hasil**: Objek `FilterResult` dengan properti:
|
|
114
|
-
- `filtered`: String teks yang sudah disensor
|
|
115
|
-
- `censored`: Jumlah kata yang disensor
|
|
116
|
-
- `replacements`: Array berisi detail kata yang disensor
|
|
117
|
-
|
|
118
|
-
##### `isProfane(text: string): boolean`
|
|
119
|
-
|
|
120
|
-
Memeriksa apakah teks mengandung kata kotor.
|
|
121
|
-
|
|
122
|
-
- **Hasil**: Boolean `true` jika teks mengandung kata kotor, `false` jika tidak
|
|
123
|
-
|
|
124
|
-
##### `analyze(text: string): AnalysisResult`
|
|
125
|
-
|
|
126
|
-
Menganalisis teks untuk mendapatkan informasi detail tentang kata kotor yang ditemukan.
|
|
127
|
-
|
|
128
|
-
- **Hasil**: Objek `AnalysisResult` dengan properti:
|
|
129
|
-
- `hasProfanity`: Apakah teks mengandung kata kotor
|
|
130
|
-
- `matches`: Array kata kotor yang ditemukan
|
|
131
|
-
- `matchDetails`: Array objek kata kotor dengan metadata
|
|
132
|
-
- `categories`: Kategori kata kotor yang ditemukan
|
|
133
|
-
- `regions`: Daerah asal kata kotor yang ditemukan
|
|
134
|
-
- `severityScore`: Skor keparahan (0-1)
|
|
135
|
-
- `similarWords`: Kata-kata yang mirip dengan kata kotor (jika deteksi kesamaan diaktifkan)
|
|
136
|
-
|
|
137
|
-
##### `batchAnalyze(texts: string[])`
|
|
138
|
-
|
|
139
|
-
Menganalisis batch teks sekaligus dan memberikan ringkasan.
|
|
140
|
-
|
|
141
|
-
- **Hasil**: Objek yang berisi ringkasan analisis
|
|
142
|
-
|
|
143
|
-
##### `analyzeBySentence(text: string)`
|
|
144
|
-
|
|
145
|
-
Menganalisis teks per-kalimat.
|
|
146
|
-
|
|
147
|
-
- **Hasil**: Array dari hasil analisis per-kalimat
|
|
148
|
-
|
|
149
|
-
##### `analyzeWithContext(text: string, contextWindowSize?: number)`
|
|
90
|
+
import IDProfanityFilter from '@sideid/id-profanity-filter';
|
|
150
91
|
|
|
151
|
-
|
|
92
|
+
const filter = new IDProfanityFilter();
|
|
152
93
|
|
|
153
|
-
|
|
94
|
+
// Gunakan preset childSafe dengan grawlix acak
|
|
95
|
+
filter.usePreset('childSafe', { useRandomGrawlix: true });
|
|
154
96
|
|
|
155
|
-
|
|
97
|
+
const hasil = filter.filter('Dasar anjing kamu!');
|
|
98
|
+
console.log(hasil.filtered);
|
|
99
|
+
// Output: "Dasar #@$%& kamu!"
|
|
100
|
+
```
|
|
156
101
|
|
|
157
|
-
|
|
102
|
+
## Dokumentasi API
|
|
158
103
|
|
|
159
|
-
|
|
160
|
-
- **additionalOptions**: Opsi tambahan untuk override preset (opsional)
|
|
104
|
+
### Kelas `IDProfanityFilter`
|
|
161
105
|
|
|
162
|
-
|
|
106
|
+
#### `constructor(options?: FilterOptions)`
|
|
107
|
+
Membuat instance filter baru dengan opsi default atau kustom.
|
|
163
108
|
|
|
164
|
-
|
|
109
|
+
#### `filter(text: string): FilterResult`
|
|
110
|
+
Menyensor kata kotor dalam teks. Mengembalikan objek:
|
|
111
|
+
- `filtered`: string hasil sensor
|
|
112
|
+
- `censored`: jumlah kata yang disensor
|
|
113
|
+
- `replacements`: daftar objek penggantian (`original`, `censored`, `metadata`)
|
|
165
114
|
|
|
166
|
-
|
|
115
|
+
#### `isProfane(text: string): boolean`
|
|
116
|
+
Mengembalikan `true` jika teks mengandung kata kotor.
|
|
167
117
|
|
|
168
|
-
|
|
118
|
+
#### `analyze(text: string): AnalysisResult`
|
|
119
|
+
Menganalisis teks secara menyeluruh. Mengembalikan objek:
|
|
120
|
+
- `hasProfanity`: boolean
|
|
121
|
+
- `matches`: string kata kotor yang cocok
|
|
122
|
+
- `matchDetails`: array objek `ProfanityWord` lengkap
|
|
123
|
+
- `categories`: kategori unik yang ditemukan
|
|
124
|
+
- `regions`: daerah asal kata yang ditemukan
|
|
125
|
+
- `severityScore`: skor keparahan kata (0 - 1)
|
|
126
|
+
- `similarWords`: kata yang mirip (jika `detectSimilarity` aktif)
|
|
169
127
|
|
|
170
|
-
|
|
128
|
+
#### `batchAnalyze(texts: string[])`
|
|
129
|
+
Menganalisis kumpulan teks sekaligus dan mengembalikan statistik agregat (total kata, teks bersih, rata-rata keparahan, kata paling sering muncul).
|
|
171
130
|
|
|
172
|
-
|
|
131
|
+
#### `analyzeBySentence(text: string)`
|
|
132
|
+
Memecah teks per kalimat dan menganalisis masing-masing kalimat secara independen.
|
|
173
133
|
|
|
174
|
-
|
|
134
|
+
#### `analyzeWithContext(text: string, contextWindowSize: number = 5)`
|
|
135
|
+
Mengambil kata kotor beserta konteks kata-kata di sekitarnya.
|
|
175
136
|
|
|
176
|
-
|
|
137
|
+
#### `setOptions(options: Partial<FilterOptions>)`
|
|
138
|
+
Memperbarui konfigurasi filter yang sedang berjalan.
|
|
177
139
|
|
|
178
|
-
|
|
140
|
+
#### `resetOptions(options: FilterOptions = {})`
|
|
141
|
+
Mengembalikan konfigurasi filter ke opsi default (dapat ditimpa dengan opsi baru).
|
|
179
142
|
|
|
180
|
-
|
|
143
|
+
#### `usePreset(presetName: string, additionalOptions?: Partial<FilterOptions>)`
|
|
144
|
+
Menerapkan preset filter (`strict`, `moderate`, `light`, `childSafe`).
|
|
181
145
|
|
|
182
|
-
|
|
146
|
+
#### `setWordList(wordList: string[])`
|
|
147
|
+
Mengatur daftar kata kustom yang akan digunakan oleh filter.
|
|
183
148
|
|
|
184
|
-
|
|
149
|
+
#### `addToWhitelist(word: string)` / `removeFromWhitelist(word: string)`
|
|
150
|
+
Menambahkan atau menghapus kata dari whitelist pengecualian.
|
|
185
151
|
|
|
186
|
-
|
|
152
|
+
#### `enableIndonesianVariations()`
|
|
153
|
+
Mengaktifkan deteksi variasi ejaan bahasa Indonesia (misalnya ejaan lama atau substitusi huruf lazim).
|
|
187
154
|
|
|
188
|
-
|
|
155
|
+
#### `enableSplitWordDetection()`
|
|
156
|
+
Mengaktifkan deteksi kata yang dipisah dengan spasi atau tanda baca (contoh: `a-n-j-i-n-g`).
|
|
189
157
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
- **maxLevenshteinDistance**: Jarak edit maksimum yang diizinkan (default: 2)
|
|
158
|
+
#### `enableSimilarityDetection(threshold = 0.8, useLevenshtein = false, maxDistance = 2)`
|
|
159
|
+
Mengaktifkan deteksi kemiripan kata untuk menangkap typo atau variasi penulisan.
|
|
193
160
|
|
|
194
|
-
|
|
161
|
+
### Opsi Filter (`FilterOptions`)
|
|
195
162
|
|
|
196
|
-
|
|
163
|
+
| Properti | Tipe | Default | Deskripsi |
|
|
164
|
+
|---|---|---|---|
|
|
165
|
+
| `replaceWith` | `string` | `'*'` | Karakter pengganti kata yang disensor |
|
|
166
|
+
| `fullWordCensor` | `boolean` | `true` | Sensor seluruh karakter kata |
|
|
167
|
+
| `keepFirstAndLast` | `boolean` | `false` | Pertahankan huruf pertama dan terakhir saat sensor (`a****g`) |
|
|
168
|
+
| `useRandomGrawlix` | `boolean` | `false` | Gunakan karakter simbol acak (`#@$%&!`) |
|
|
169
|
+
| `detectLeetSpeak` | `boolean` | `true` | Deteksi variasi angka/simbol (`b4b1`, `4nj1ng`) |
|
|
170
|
+
| `detectSplit` | `boolean` | `false` | Deteksi kata dengan pemisah (`b-a-b-i`) |
|
|
171
|
+
| `indonesianVariation` | `boolean` | `false` | Deteksi variasi ejaan Indonesia |
|
|
172
|
+
| `detectSimilarity` | `boolean` | `false` | Deteksi kata typo atau mirip |
|
|
173
|
+
| `similarityThreshold` | `number` | `0.8` | Batas minimum kemiripan (0 - 1) |
|
|
174
|
+
| `useLevenshtein` | `boolean` | `false` | Gunakan algoritma Levenshtein distance |
|
|
175
|
+
| `maxLevenshteinDistance` | `number` | `2` | Jarak edit maksimum Levenshtein |
|
|
176
|
+
| `checkSubstring` | `boolean` | `false` | Deteksi kata kotor di dalam substring kata lain |
|
|
177
|
+
| `wordList` | `string[]` | `[]` | Daftar kata kustom (menggantikan daftar bawaan) |
|
|
178
|
+
| `whitelist` | `string[]` | `[]` | Daftar kata yang diabaikan dari filter |
|
|
179
|
+
| `categories` | `ProfanityCategory[]` | - | Filter hanya kategori tertentu |
|
|
180
|
+
| `regions` | `Region[]` | - | Filter hanya daerah tertentu |
|
|
181
|
+
| `severityThreshold` | `number` | `0` | Batas keparahan minimum kata (0 - 1) |
|
|
197
182
|
|
|
198
|
-
|
|
199
|
-
- **maxDistance**: Jarak edit maksimum yang diizinkan (default: 2)
|
|
183
|
+
## Contoh penggunaan lanjutan
|
|
200
184
|
|
|
201
|
-
###
|
|
185
|
+
### Daftar kata kustom
|
|
202
186
|
|
|
203
187
|
```typescript
|
|
204
|
-
|
|
205
|
-
// Opsi dasar
|
|
206
|
-
wordList?: string[]; // List kata yang ingin difilter
|
|
207
|
-
replaceWith?: string; // Karakter pengganti untuk kata yang disensor
|
|
208
|
-
fullWordCensor?: boolean; // Apakah menyensor seluruh kata atau sebagian
|
|
209
|
-
detectLeetSpeak?: boolean; // Deteksi variasi penulisan (mis: a=4, e=3)
|
|
210
|
-
whitelist?: string[]; // Kata-kata yang dikecualikan dari filter
|
|
211
|
-
checkSubstring?: boolean; // Memeriksa substring (lebih ketat)
|
|
212
|
-
categories?: ProfanityCategory[]; // Kategori kata yang difilter
|
|
213
|
-
regions?: Region[]; // Daerah asal kata yang difilter
|
|
214
|
-
severityThreshold?: number; // Tingkat keparahan minimum (0-1)
|
|
215
|
-
|
|
216
|
-
// Opsi lanjutan
|
|
217
|
-
useRandomGrawlix?: boolean; // Gunakan karakter acak untuk sensor (#@$%&!)
|
|
218
|
-
keepFirstAndLast?: boolean; // Simpan huruf pertama dan terakhir (a***g)
|
|
219
|
-
indonesianVariation?: boolean; // Deteksi variasi ejaan Bahasa Indonesia
|
|
220
|
-
detectSimilarity?: boolean; // Deteksi kata berdasarkan kesamaan
|
|
221
|
-
similarityThreshold?: number; // Ambang batas kesamaan (0-1)
|
|
222
|
-
detectSplit?: boolean; // Deteksi kata yang dipisah (a-n-j-i-n-g)
|
|
223
|
-
useLevenshtein?: boolean; // Gunakan algoritma Levenshtein untuk deteksi kesamaan
|
|
224
|
-
maxLevenshteinDistance?: number; // Jarak edit maksimum untuk deteksi Levenshtein
|
|
225
|
-
}
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
## Preset Filter
|
|
229
|
-
|
|
230
|
-
Library ini menyediakan beberapa preset yang dapat digunakan:
|
|
231
|
-
|
|
232
|
-
### Preset Filter
|
|
233
|
-
|
|
234
|
-
- **strict**: Filter paling ketat, mendeteksi semua jenis kata kotor
|
|
235
|
-
- **moderate**: Filter tingkat menengah, mengabaikan kata-kata dengan tingkat keparahan rendah
|
|
236
|
-
- **light**: Filter ringan, hanya untuk kata-kata paling sensitif
|
|
237
|
-
- **childSafe**: Filter untuk konten anak-anak, sangat ketat
|
|
238
|
-
|
|
239
|
-
### Preset Kategori
|
|
240
|
-
|
|
241
|
-
- **sexual**: Hanya memfilter kata-kata berbau seksual
|
|
242
|
-
- **insults**: Hanya memfilter kata-kata penghinaan
|
|
243
|
-
- **profanity**: Hanya memfilter umpatan umum
|
|
244
|
-
|
|
245
|
-
### Preset Regional
|
|
246
|
-
|
|
247
|
-
- **general**: Hanya memfilter kata-kata umum di Indonesia
|
|
248
|
-
- **jawa**: Hanya memfilter kata-kata dari Jawa
|
|
249
|
-
- **sunda**: Hanya memfilter kata-kata dari Sunda
|
|
250
|
-
- **betawi**: Hanya memfilter kata-kata dari Betawi
|
|
251
|
-
- **batak**: Hanya memfilter kata-kata dari Batak
|
|
252
|
-
|
|
253
|
-
## Contoh Penggunaan Lanjutan
|
|
254
|
-
|
|
255
|
-
### Kustomisasi Opsi Filter
|
|
188
|
+
import IDProfanityFilter from '@sideid/id-profanity-filter';
|
|
256
189
|
|
|
257
|
-
```typescript
|
|
258
190
|
const filter = new IDProfanityFilter({
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
detectLeetSpeak: true, // Mendeteksi variasi seperti "b4b1" untuk "babi"
|
|
262
|
-
categories: ['sexual', 'slur'], // Hanya filter kategori tertentu
|
|
263
|
-
regions: ['jawa', 'general'], // Hanya filter dari daerah tertentu
|
|
264
|
-
severityThreshold: 0.7, // Hanya filter kata dengan tingkat keparahan ≥ 0.7
|
|
265
|
-
|
|
266
|
-
// Opsi lanjutan
|
|
267
|
-
useRandomGrawlix: true, // Gunakan #@$%&! sebagai karakter pengganti
|
|
268
|
-
keepFirstAndLast: true, // Simpan huruf pertama dan terakhir (a***g)
|
|
269
|
-
indonesianVariation: true, // Deteksi variasi ejaan Indonesia
|
|
270
|
-
detectSimilarity: true, // Deteksi kata yang mirip
|
|
271
|
-
similarityThreshold: 0.8, // Ambang batas kesamaan
|
|
272
|
-
detectSplit: true, // Deteksi kata yang dipisah
|
|
273
|
-
useLevenshtein: true, // Gunakan algoritma Levenshtein
|
|
274
|
-
maxLevenshteinDistance: 2, // Jarak Levenshtein maksimum
|
|
191
|
+
wordList: ['jelek', 'payah', 'curang'],
|
|
192
|
+
replaceWith: '#',
|
|
275
193
|
});
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Menggunakan Whitelist
|
|
279
|
-
|
|
280
|
-
```typescript
|
|
281
|
-
const filter = new IDProfanityFilter();
|
|
282
|
-
|
|
283
|
-
// Menambahkan kata ke whitelist (akan diabaikan)
|
|
284
|
-
filter.addToWhitelist('anjing');
|
|
285
194
|
|
|
286
|
-
const teks =
|
|
287
|
-
'Anjing itu hewan peliharaan yang setia, tidak seperti bajingan itu';
|
|
195
|
+
const teks = 'Kualitas layanannya sangat jelek dan payah!';
|
|
288
196
|
const hasil = filter.filter(teks);
|
|
289
197
|
|
|
290
198
|
console.log(hasil.filtered);
|
|
291
|
-
// Output: "
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
### Deteksi Variasi Ejaan dan Kata Terpisah
|
|
295
|
-
|
|
296
|
-
```typescript
|
|
297
|
-
// Aktifkan deteksi variasi ejaan dan kata terpisah
|
|
298
|
-
const filter = new IDProfanityFilter({
|
|
299
|
-
indonesianVariation: true,
|
|
300
|
-
detectSplit: true,
|
|
301
|
-
detectLeetSpeak: true,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
// Uji dengan variasi ejaan
|
|
305
|
-
const teks1 = 'Dasar kamu ini sangat bodoh, benar-benar b0d0h dan b-o-d-o-h!';
|
|
306
|
-
const hasil1 = filter.filter(teks1);
|
|
307
|
-
console.log(hasil1.filtered);
|
|
308
|
-
// Output: "Dasar kamu ini sangat *****, benar-benar ***** dan *********!"
|
|
309
|
-
|
|
310
|
-
// Uji dengan ejaan Indonesia yang berbeda
|
|
311
|
-
const teks2 = 'Dia sangat djail dan djudes dengan temannya';
|
|
312
|
-
const hasil2 = filter.filter(teks2);
|
|
313
|
-
console.log(hasil2.filtered);
|
|
314
|
-
// Output: "Dia sangat ***** dan ****** dengan temannya"
|
|
199
|
+
// Output: "Kualitas layanannya sangat ##### dan #####!"
|
|
315
200
|
```
|
|
316
201
|
|
|
317
|
-
### Deteksi
|
|
202
|
+
### Deteksi typo dan Levenshtein distance
|
|
318
203
|
|
|
319
204
|
```typescript
|
|
320
|
-
|
|
321
|
-
const filter = new IDProfanityFilter();
|
|
322
|
-
filter.enableSimilarityDetection(0.75); // Set threshold kesamaan ke 0.75
|
|
323
|
-
|
|
324
|
-
const teks = 'Dia benar-benar anjiing dan gooblok!';
|
|
325
|
-
const analisis = filter.analyze(teks);
|
|
326
|
-
|
|
327
|
-
console.log(analisis.similarWords);
|
|
328
|
-
/* Output:
|
|
329
|
-
[
|
|
330
|
-
{ word: "anjiing", original: "anjing", similarity: 0.83 },
|
|
331
|
-
{ word: "gooblok", original: "goblok", similarity: 0.85 }
|
|
332
|
-
]
|
|
333
|
-
*/
|
|
334
|
-
|
|
335
|
-
const hasil = filter.filter(teks);
|
|
336
|
-
console.log(hasil.filtered);
|
|
337
|
-
// Output: "Dia benar-benar ****** dan *******!"
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### Deteksi dengan Algoritma Levenshtein Distance
|
|
205
|
+
import IDProfanityFilter from '@sideid/id-profanity-filter';
|
|
341
206
|
|
|
342
|
-
```typescript
|
|
343
|
-
// Aktifkan deteksi menggunakan algoritma Levenshtein Distance
|
|
344
207
|
const filter = new IDProfanityFilter();
|
|
345
|
-
filter.enableLevenshteinDetection(0.
|
|
346
|
-
// Threshold 0.85, maksimal 2 karakter berbeda
|
|
208
|
+
filter.enableLevenshteinDetection(0.8, 2);
|
|
347
209
|
|
|
348
|
-
const teks = 'Dia benar-benar
|
|
210
|
+
const teks = 'Dia benar-benar anjiing sekali!';
|
|
349
211
|
const hasil = filter.filter(teks);
|
|
350
212
|
|
|
351
213
|
console.log(hasil.filtered);
|
|
352
|
-
// Output: "Dia benar-benar *******
|
|
353
|
-
|
|
354
|
-
// Atau menggunakan opsi langsung:
|
|
355
|
-
const filterCustom = new IDProfanityFilter({
|
|
356
|
-
detectSimilarity: true,
|
|
357
|
-
useLevenshtein: true,
|
|
358
|
-
similarityThreshold: 0.85,
|
|
359
|
-
maxLevenshteinDistance: 2,
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
// Mendeteksi typo atau variasi disengaja
|
|
363
|
-
const teksVariasi = 'kontool kamu kwontol anjiing';
|
|
364
|
-
console.log(filterCustom.filter(teksVariasi).filtered);
|
|
365
|
-
// Output: "******* kamu ******* ******"
|
|
214
|
+
// Output: "Dia benar-benar ******* sekali!"
|
|
366
215
|
```
|
|
367
216
|
|
|
368
|
-
###
|
|
217
|
+
### Whitelist kontekstual
|
|
369
218
|
|
|
370
219
|
```typescript
|
|
371
|
-
|
|
372
|
-
const filter1 = new IDProfanityFilter();
|
|
373
|
-
console.log(filter1.filter('Dasar anjing kamu!').filtered);
|
|
374
|
-
// Output: "Dasar ***** kamu!"
|
|
375
|
-
|
|
376
|
-
// Sensor dengan grawlix random
|
|
377
|
-
const filter2 = new IDProfanityFilter({ useRandomGrawlix: true });
|
|
378
|
-
console.log(filter2.filter('Dasar anjing kamu!').filtered);
|
|
379
|
-
// Output: "Dasar #@$%& kamu!"
|
|
380
|
-
|
|
381
|
-
// Sensor dengan menyimpan huruf pertama dan terakhir
|
|
382
|
-
const filter3 = new IDProfanityFilter({
|
|
383
|
-
fullWordCensor: false,
|
|
384
|
-
keepFirstAndLast: true,
|
|
385
|
-
});
|
|
386
|
-
console.log(filter3.filter('Dasar anjing kamu!').filtered);
|
|
387
|
-
// Output: "Dasar a***g kamu!"
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
### Analisis Konten Mendalam
|
|
220
|
+
import IDProfanityFilter from '@sideid/id-profanity-filter';
|
|
391
221
|
|
|
392
|
-
```typescript
|
|
393
222
|
const filter = new IDProfanityFilter();
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
// Analisis teks
|
|
397
|
-
const analisis = filter.analyze(teks);
|
|
398
|
-
console.log(analisis);
|
|
399
|
-
|
|
400
|
-
/* Output:
|
|
401
|
-
{
|
|
402
|
-
hasProfanity: true,
|
|
403
|
-
matches: ['anjing', 'sialan', 'bego', 'goblok'],
|
|
404
|
-
matchDetails: [
|
|
405
|
-
{ word: 'anjing', category: 'profanity', region: 'general', severity: 0.7, ... },
|
|
406
|
-
{ word: 'bego', category: 'insult', region: 'general', severity: 0.5, ... },
|
|
407
|
-
...
|
|
408
|
-
],
|
|
409
|
-
categories: ['profanity', 'insult'],
|
|
410
|
-
regions: ['general'],
|
|
411
|
-
severityScore: 0.64
|
|
412
|
-
}
|
|
413
|
-
*/
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
### Analisis Konteks
|
|
223
|
+
filter.addToWhitelist('anjing');
|
|
417
224
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const teks =
|
|
421
|
-
'Saya sangat marah dengan sikapnya, dia benar-benar anjing dan bajingan!';
|
|
422
|
-
|
|
423
|
-
// Analisis konteks
|
|
424
|
-
const konteks = filter.analyzeWithContext(teks, 3);
|
|
425
|
-
console.log(konteks);
|
|
426
|
-
|
|
427
|
-
/* Output:
|
|
428
|
-
[
|
|
429
|
-
{
|
|
430
|
-
word: "anjing",
|
|
431
|
-
context: "benar-benar anjing dan bajingan",
|
|
432
|
-
position: { start: 43, end: 62 }
|
|
433
|
-
},
|
|
434
|
-
{
|
|
435
|
-
word: "bajingan",
|
|
436
|
-
context: "anjing dan bajingan!",
|
|
437
|
-
position: { start: 54, end: 63 }
|
|
438
|
-
}
|
|
439
|
-
]
|
|
440
|
-
*/
|
|
225
|
+
const teks = 'Anjing peliharaan saya setia sekali.';
|
|
226
|
+
console.log(filter.isProfane(teks)); // false
|
|
441
227
|
```
|
|
442
228
|
|
|
443
|
-
### Analisis
|
|
229
|
+
### Analisis per kalimat
|
|
444
230
|
|
|
445
231
|
```typescript
|
|
446
|
-
|
|
447
|
-
const teks =
|
|
448
|
-
'Filmnya bagus sekali. Tetapi pemainnya seperti anjing, sangat buruk aktingnya.';
|
|
449
|
-
|
|
450
|
-
// Analisis per-kalimat
|
|
451
|
-
const kalimat = filter.analyzeBySentence(teks);
|
|
452
|
-
console.log(
|
|
453
|
-
kalimat.map(
|
|
454
|
-
(k) =>
|
|
455
|
-
k.sentence + (k.hasProfanity ? ' (Mengandung kata kotor)' : ' (Bersih)'),
|
|
456
|
-
),
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
/* Output:
|
|
460
|
-
[
|
|
461
|
-
"Filmnya bagus sekali. (Bersih)",
|
|
462
|
-
"Tetapi pemainnya seperti anjing, sangat buruk aktingnya. (Mengandung kata kotor)"
|
|
463
|
-
]
|
|
464
|
-
*/
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
### Analisis Batch
|
|
232
|
+
import IDProfanityFilter from '@sideid/id-profanity-filter';
|
|
468
233
|
|
|
469
|
-
```typescript
|
|
470
234
|
const filter = new IDProfanityFilter();
|
|
471
|
-
const
|
|
472
|
-
'Film ini sangat bagus, ceritanya menarik sekali!',
|
|
473
|
-
'Dasar goblok, sialan kamu!',
|
|
474
|
-
'Anjing emang filmnya, sampah banget.',
|
|
475
|
-
];
|
|
476
|
-
|
|
477
|
-
const hasil = filter.batchAnalyze(komentar);
|
|
478
|
-
console.log(hasil);
|
|
479
|
-
|
|
480
|
-
/* Output:
|
|
481
|
-
{
|
|
482
|
-
totalTexts: 3,
|
|
483
|
-
profaneTexts: 2,
|
|
484
|
-
cleanTexts: 1,
|
|
485
|
-
averageSeverity: 0.62,
|
|
486
|
-
topCategories: ['profanity', 'insult'],
|
|
487
|
-
topRegions: ['general'],
|
|
488
|
-
mostFrequentWords: [
|
|
489
|
-
{ word: 'anjing', count: 1 },
|
|
490
|
-
{ word: 'goblok', count: 1 },
|
|
491
|
-
{ word: 'sialan', count: 1 },
|
|
492
|
-
{ word: 'sampah', count: 1 }
|
|
493
|
-
]
|
|
494
|
-
}
|
|
495
|
-
*/
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
## Dukungan Regional
|
|
499
|
-
|
|
500
|
-
Library ini mendukung kata-kata kotor dari berbagai daerah di Indonesia:
|
|
501
|
-
|
|
502
|
-
- 🇮🇩 **General** - Kata-kata yang umum di seluruh Indonesia
|
|
503
|
-
- 🏝️ **Jawa** - Kata-kata dari bahasa Jawa
|
|
504
|
-
- 🏞️ **Sunda** - Kata-kata dari bahasa Sunda
|
|
505
|
-
- 🏙️ **Betawi** - Kata-kata dari bahasa Betawi
|
|
506
|
-
- 🌋 **Batak** - Kata-kata dari bahasa Batak
|
|
507
|
-
|
|
508
|
-
## Kategori Kata
|
|
509
|
-
|
|
510
|
-
Kata-kata dikelompokkan berdasarkan kategori:
|
|
235
|
+
const teks = 'Filmnya bagus sekali. Tapi pemainnya seperti anjing, aktingnya buruk.';
|
|
511
236
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
237
|
+
const hasilKalimat = filter.analyzeBySentence(teks);
|
|
238
|
+
hasilKalimat.forEach((item) => {
|
|
239
|
+
console.log(`${item.sentence} -> ${item.hasProfanity ? 'Kotor' : 'Bersih'}`);
|
|
240
|
+
});
|
|
241
|
+
// "Filmnya bagus sekali." -> Bersih
|
|
242
|
+
// "Tapi pemainnya seperti anjing, aktingnya buruk." -> Kotor
|
|
243
|
+
```
|
|
519
244
|
|
|
520
|
-
##
|
|
245
|
+
## Cakupan daerah dan kategori
|
|
521
246
|
|
|
522
|
-
|
|
247
|
+
### Bahasa daerah
|
|
248
|
+
- `general`: Bahasa Indonesia umum
|
|
249
|
+
- `jawa`: Bahasa Jawa
|
|
250
|
+
- `sunda`: Bahasa Sunda
|
|
251
|
+
- `betawi`: Dialek Betawi
|
|
252
|
+
- `batak`: Bahasa Batak
|
|
253
|
+
- `minang`: Bahasa Minang
|
|
254
|
+
- `bali`: Bahasa Bali
|
|
255
|
+
- `madura`: Bahasa Madura
|
|
256
|
+
- `aceh`: Bahasa Aceh
|
|
523
257
|
|
|
524
|
-
###
|
|
258
|
+
### Kategori kata
|
|
259
|
+
- `sexual`: Istilah atau aktivitas seksual vulgar
|
|
260
|
+
- `insult`: Penghinaan atau caci maki
|
|
261
|
+
- `profanity`: Umpatan kasar umum
|
|
262
|
+
- `slur`: Kata merendahkan SARA / identitas
|
|
263
|
+
- `drugs`: Istilah obat-obatan terlarang
|
|
264
|
+
- `disgusting`: Kata jorok atau menjijikkan
|
|
265
|
+
- `blasphemy`: Umpatan penistaan agama
|
|
525
266
|
|
|
526
|
-
|
|
267
|
+
## Kontribusi
|
|
527
268
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
```json
|
|
531
|
-
{
|
|
532
|
-
"word": "kata_kotor", // Kata yang akan difilter
|
|
533
|
-
"category": "insult", // Kategori kata
|
|
534
|
-
"region": "general", // Daerah asal kata
|
|
535
|
-
"severity": 0.7, // Tingkat keparahan (0-1)
|
|
536
|
-
"aliases": ["k4t4_kotor", "kata_k0t0r"], // Alias atau variasi umum
|
|
537
|
-
"description": "Deskripsi tentang kata", // Penjelasan tentang kata (opsional)
|
|
538
|
-
"context": "Konteks penggunaan kata" // Konteks penggunaan (opsional)
|
|
539
|
-
}
|
|
540
|
-
```
|
|
269
|
+
Panduan untuk menambahkan kata baru atau mengembangkan library dapat dilihat di [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
541
270
|
|
|
542
271
|
## Lisensi
|
|
543
272
|
|
|
544
|
-
Proyek ini
|
|
545
|
-
|
|
546
|
-
## Kontak & Dukungan
|
|
547
|
-
|
|
548
|
-
Jika Anda memiliki pertanyaan atau saran, silakan buka issue di repositori GitHub kami.
|
|
273
|
+
Proyek ini menggunakan lisensi [MIT](LICENSE).
|