diff --git a/.travis.yml b/.travis.yml index 65ec28e..87a5c32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,11 +5,18 @@ python: - "3.4" - "3.5" sudo: false +# Enable 3.7 without globally enabling sudo and dist: xenial for other build jobs +matrix: + include: + - python: 3.7 + dist: xenial + sudo: true install: - pip install python-coveralls - pip install coveralls + - pip install cachetools script: nosetests tests --verbose --with-coverage after_success: - coveralls notifications: - email: false + email: false \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..500bc70 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.linting.pylintEnabled": true +} \ No newline at end of file diff --git a/README.md b/README.md index f1184ff..6fc8dd0 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,4 @@ -Sastrawi Python -=============== +# sastrawi +Indonesian stemmer. Python port of PHP Sastrawi project. -Sastrawi Python is a simple python library which allows you to reduce inflected words in Indonesian Language (Bahasa Indonesia) to their base form ([stem](http://en.wikipedia.org/wiki/Stemming)). -This is Python port of the original [Sastrawi](https://github.com/sastrawi/sastrawi) project written in PHP (credits goes to the original author and contributors of Sastrawi PHP). - - -[![Build Status](https://travis-ci.org/har07/PySastrawi.svg?branch=master)](https://travis-ci.org/har07/PySastrawi) -[![Coverage Status](https://coveralls.io/repos/github/har07/PySastrawi/badge.svg?branch=master)](https://coveralls.io/github/har07/PySastrawi?branch=master) -[![PyPI version](https://badge.fury.io/py/PySastrawi.svg)](https://badge.fury.io/py/PySastrawi) - -Cara Install -------------- - -Sastrawi dapat di-*install* menggunakan [pip](https://docs.python.org/3.6/installing/index.html), dengan menjalankan perintah berikut di terminal/command prompt : `pip install PySastrawi` - -Penggunaan ------------ - -Jalankan baris-baris kode berikut di *Python interactive terminal* : - -```python -# import StemmerFactory class -from Sastrawi.Stemmer.StemmerFactory import StemmerFactory - -# create stemmer -factory = StemmerFactory() -stemmer = factory.create_stemmer() - -# stemming process -sentence = 'Perekonomian Indonesia sedang dalam pertumbuhan yang membanggakan' -output = stemmer.stem(sentence) - -print(output) -# ekonomi indonesia sedang dalam tumbuh yang bangga - -print(stemmer.stem('Mereka meniru-nirukannya')) -# mereka tiru -``` - -Demo --------- - -Live demo URL : https://pysastrawi-demo.appspot.com/ - -Repository : https://github.com/har07/pystastrawi-demo - -Lisensi --------- - -Lisensi Sastrawi Python adalah MIT License (MIT). - -Project ini mengandung kamus kata dasar yang berasal dari Kateglo dengan lisensi [CC-BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/). - -Informasi Lebih Lanjut ----------------------- - -- [Sastrawi PHP Repository page](https://github.com/sastrawi/sastrawi) +[![Coverage Status](https://coveralls.io/repos/har07/sastrawi/badge.svg?branch=development&service=github)](https://coveralls.io/github/har07/sastrawi?branch=development) \ No newline at end of file diff --git a/src/Sastrawi/Dictionary/ArrayDictionary.py b/src/Sastrawi/Dictionary/ArrayDictionary.py index 5bfdd90..814cf6b 100644 --- a/src/Sastrawi/Dictionary/ArrayDictionary.py +++ b/src/Sastrawi/Dictionary/ArrayDictionary.py @@ -1,10 +1,17 @@ -class ArrayDictionary(object): +from Sastrawi.Dictionary.DictionaryInterface import DictionaryInterface + +class ArrayDictionary(DictionaryInterface): """description of class""" def __init__(self, words=None): - self.words = {} - if words: + if words is None: + self.words = {} + elif type(words) is dict: + self.words = words + elif type(words) is list: self.add_words(words) + else: + self.words = {} def contains(self, word): return word in self.words @@ -20,9 +27,4 @@ def add(self, word): """Add a word to the dictionary""" if not word or word.strip() == '': return - self.words[word]=word - - - - - + self.words[word] = word \ No newline at end of file diff --git a/src/Sastrawi/Dictionary/DictionaryInterface.py b/src/Sastrawi/Dictionary/DictionaryInterface.py index f899ae4..46433b6 100644 --- a/src/Sastrawi/Dictionary/DictionaryInterface.py +++ b/src/Sastrawi/Dictionary/DictionaryInterface.py @@ -1,5 +1,12 @@ -class DictionaryInterface(object): +# @update_by Mufid Jamaluddin +# @update_date 16/03/2019 + +from abc import ABCMeta, abstractmethod + +class DictionaryInterface: """Interface definition of dictionary""" + __metaclass__ = ABCMeta + @abstractmethod def contains(self, word): - raise NotImplementedError('you must implement this method manually') \ No newline at end of file + pass \ No newline at end of file diff --git a/src/Sastrawi/Stemmer/Cache/ArrayCache.py b/src/Sastrawi/Stemmer/Cache/ArrayCache.py deleted file mode 100644 index 35ff2b3..0000000 --- a/src/Sastrawi/Stemmer/Cache/ArrayCache.py +++ /dev/null @@ -1,19 +0,0 @@ -from Sastrawi.Stemmer.Cache.CacheInterface import CacheInterface - -class ArrayCache(CacheInterface): - """description of class""" - - def __init__(self): - self.data = {} - - def set(self, key, value): - self.data[key] = value - - def get(self, key): - if key in self.data: - return self.data[key] - - def has(self, key): - return key in self.data - - diff --git a/src/Sastrawi/Stemmer/Cache/CacheInterface.py b/src/Sastrawi/Stemmer/Cache/CacheInterface.py deleted file mode 100644 index cbed596..0000000 --- a/src/Sastrawi/Stemmer/Cache/CacheInterface.py +++ /dev/null @@ -1,13 +0,0 @@ -class CacheInterface(object): - """description of class""" - - def has(self, key): - pass - - def set(self, key, value): - pass - - def get(self, key): - pass - - diff --git a/src/Sastrawi/Stemmer/Cache/__init__.py b/src/Sastrawi/Stemmer/Cache/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/Sastrawi/Stemmer/CachedStemmer.py b/src/Sastrawi/Stemmer/CachedStemmer.py deleted file mode 100644 index 97258bc..0000000 --- a/src/Sastrawi/Stemmer/CachedStemmer.py +++ /dev/null @@ -1,27 +0,0 @@ -#from Sastrawi.Stemmer.StemmerInterface import StemmerInterface -from Sastrawi.Stemmer.Filter import TextNormalizer - -class CachedStemmer(object): - """description of class""" - def __init__(self, cache, delegatedStemmer): - self.cache = cache - self.delegatedStemmer = delegatedStemmer - - def stem(self, text): - normalizedText = TextNormalizer.normalize_text(text) - - words = normalizedText.split(' ') - stems = [] - - for word in words: - if self.cache.has(word): - stems.append(self.cache.get(word)) - else: - stem = self.delegatedStemmer.stem(word) - self.cache.set(word, stem) - stems.append(stem) - - return ' '.join(stems) - - def get_cache(self): - return self.cache diff --git a/src/Sastrawi/Stemmer/Context/Context.py b/src/Sastrawi/Stemmer/Context/Context.py index 18223ee..6667714 100644 --- a/src/Sastrawi/Stemmer/Context/Context.py +++ b/src/Sastrawi/Stemmer/Context/Context.py @@ -160,5 +160,4 @@ def restore_prefix(self): for removal in self.removals: if removal.get_affix_type() == 'DP': - self.removals.remove(removal) - + self.removals.remove(removal) \ No newline at end of file diff --git a/src/Sastrawi/Stemmer/Context/ContextInterface.py b/src/Sastrawi/Stemmer/Context/ContextInterface.py index 180c6d0..5a3b7be 100644 --- a/src/Sastrawi/Stemmer/Context/ContextInterface.py +++ b/src/Sastrawi/Stemmer/Context/ContextInterface.py @@ -1,30 +1,40 @@ -class ContextInterface(object): - """description of class""" +# @update_by Mufid Jamaluddin +# @update_date 16/03/2019 +from abc import ABCMeta, abstractmethod + +class ContextInterface: + """description of abs class""" + __metaclass__ = ABCMeta + + @abstractmethod def getOriginalWord(self): pass + @abstractmethod def setCurrentWord(self, word): pass + @abstractmethod def getCurrentWord(self): pass + @abstractmethod def getDictionary(self): pass + @abstractmethod def stopProcess(self): pass + @abstractmethod def processIsStopped(self): pass + @abstractmethod def addRemoval(self, removal): pass + @abstractmethod def getRemovals(self): - pass - - - - + pass \ No newline at end of file diff --git a/src/Sastrawi/Stemmer/Context/RemovalInterface.py b/src/Sastrawi/Stemmer/Context/RemovalInterface.py index 93b6171..a94a18f 100644 --- a/src/Sastrawi/Stemmer/Context/RemovalInterface.py +++ b/src/Sastrawi/Stemmer/Context/RemovalInterface.py @@ -1,18 +1,29 @@ -class RemovalInterface(object): +# @update_by Mufid Jamaluddin +# @update_date 16/03/2019 + +from abc import ABCMeta, abstractmethod + +class RemovalInterface: """description of class""" + __metaclass__ = ABCMeta + @abstractmethod def get_visitor(self): pass + @abstractmethod def get_subject(self): pass + @abstractmethod def get_result(self): pass + @abstractmethod def get_removed_part(self): pass + @abstractmethod def get_affix_type(self): pass diff --git a/src/Sastrawi/Stemmer/Stemmer.py b/src/Sastrawi/Stemmer/Stemmer.py index cb196c7..1f3135e 100644 --- a/src/Sastrawi/Stemmer/Stemmer.py +++ b/src/Sastrawi/Stemmer/Stemmer.py @@ -2,6 +2,7 @@ from Sastrawi.Stemmer.Context.Visitor.VisitorProvider import VisitorProvider from Sastrawi.Stemmer.Filter import TextNormalizer from Sastrawi.Stemmer.Context.Context import Context +from cachetools import cached, LRUCache class Stemmer(object): """Indonesian Stemmer. @@ -35,6 +36,16 @@ def stem_word(self, word): else: return self.stem_singular_word(word) + # Stemming word in Tokens + # @author Mufid Jamaluddin + def stem_tokens(self, tokens): + stemmed_tokens = [] + for token in tokens: + if not token or token.strip() == '': + continue + stemmed_tokens.append(self.stem_word(token)) + return stemmed_tokens + def is_plural(self, word): #-ku|-mu|-nya #nikmat-Ku, etc diff --git a/src/Sastrawi/Stemmer/StemmerFactory.py b/src/Sastrawi/Stemmer/StemmerFactory.py index 10e6aaa..dd16bb5 100644 --- a/src/Sastrawi/Stemmer/StemmerFactory.py +++ b/src/Sastrawi/Stemmer/StemmerFactory.py @@ -1,43 +1,37 @@ import os +from cachetools import cached, LRUCache from Sastrawi.Dictionary.ArrayDictionary import ArrayDictionary from Sastrawi.Stemmer.Stemmer import Stemmer -from Sastrawi.Stemmer.CachedStemmer import CachedStemmer -from Sastrawi.Stemmer.Cache.ArrayCache import ArrayCache class StemmerFactory(object): """ Stemmer factory helps creating pre-configured stemmer """ - APC_KEY = 'sastrawi_cache_dictionary' def create_stemmer(self, isDev=False): """ Returns Stemmer instance """ + if isDev: + words = self.get_words_from_file() + dictionary = ArrayDictionary(words) + else: + dictionary = self.get_prod_words_dictionary() - words = self.get_words(isDev) - dictionary = ArrayDictionary(words) stemmer = Stemmer(dictionary) - resultCache = ArrayCache() - cachedStemmer = CachedStemmer(resultCache, stemmer) - - return cachedStemmer + return stemmer - def get_words(self, isDev=False): - #if isDev or callable(getattr(self, 'apc_fetch')): - # words = self.getWordsFromFile() - #else: - # words = apc_fetch(self.APC_KEY) - # if not words: - # words = self.getWordsFromFile() - # apc_store(self.APC_KEY, words) - return self.get_words_from_file() + @cached(cache=LRUCache(maxsize=32)) + def get_prod_words_dictionary(self): + words = self.get_words_from_file() + dictionary = ArrayDictionary(words) + return dictionary def get_words_from_file(self): current_dir = os.path.dirname(os.path.realpath(__file__)) dictionaryFile = current_dir + '/data/kata-dasar.txt' + if not os.path.isfile(dictionaryFile): raise RuntimeError('Dictionary file is missing. It seems that your installation is corrupted.') - dictionaryContent = '' + text = '' with open(dictionaryFile, 'r') as f: - dictionaryContent = f.read() - - return dictionaryContent.split('\n') \ No newline at end of file + text = f.read() + return text.split('\n') \ No newline at end of file diff --git a/src/Sastrawi/StopWordRemover/StopWordRemover.py b/src/Sastrawi/StopWordRemover/StopWordRemover.py index d3de2ff..a5bbd3e 100644 --- a/src/Sastrawi/StopWordRemover/StopWordRemover.py +++ b/src/Sastrawi/StopWordRemover/StopWordRemover.py @@ -14,6 +14,8 @@ def remove(self, text): return ' '.join(stopped_words) - - - + # Remove Stopword in Tokens + # @author Mufid Jamaluddin + def remove_tokens(self, tokens): + clean_tokens = [token for token in tokens if not self.dictionary.contains(token)] + return clean_tokens \ No newline at end of file diff --git a/src/Sastrawi/StopWordRemover/StopWordRemoverFactory.py b/src/Sastrawi/StopWordRemover/StopWordRemoverFactory.py index 560db07..668ed94 100644 --- a/src/Sastrawi/StopWordRemover/StopWordRemoverFactory.py +++ b/src/Sastrawi/StopWordRemover/StopWordRemoverFactory.py @@ -1,109 +1,34 @@ +import os +from cachetools import cached, LRUCache from Sastrawi.Dictionary.ArrayDictionary import ArrayDictionary from Sastrawi.StopWordRemover.StopWordRemover import StopWordRemover class StopWordRemoverFactory(object): """description of class""" - def create_stop_word_remover(self): - stopWords = self.get_stop_words() - dictionary = ArrayDictionary(stopWords) - stopWordRemover = StopWordRemover(dictionary) + def create_stop_word_remover(self, isDev=False): + if isDev: + stopWords = self.get_stop_words() + dictionary = ArrayDictionary(stopWords) + else: + dictionary = self.get_prod_stop_word_dictionary() + stopWordRemover = StopWordRemover(dictionary) return stopWordRemover - def get_stop_words(self): - return ['a','ada','adalah','adanya','adapun','agak','agaknya','agar','akan','akankah','akhir', - 'akhiri','akhirnya','aku','akulah','amat','amatlah','anda','andalah','antar','antara', - 'antaranya','apa','apaan','apabila','apakah','apalagi','apatah','arti','artinya','asal', - 'asalkan','atas','atau','ataukah','ataupun','awal','awalnya','b','bagai','bagaikan', - 'bagaimana','bagaimanakah','bagaimanapun','bagainamakah','bagi','bagian','bahkan','bahwa', - 'bahwasannya','bahwasanya','baik','baiklah','bakal','bakalan','balik','banyak','bapak', - 'baru','bawah','beberapa','begini','beginian','beginikah','beginilah','begitu','begitukah', - 'begitulah','begitupun','bekerja','belakang','belakangan','belum','belumlah','benar', - 'benarkah','benarlah','berada','berakhir','berakhirlah','berakhirnya','berapa','berapakah', - 'berapalah','berapapun','berarti','berawal','berbagai','berdatangan','beri','berikan', - 'berikut','berikutnya','berjumlah','berkali-kali','berkata','berkehendak','berkeinginan', - 'berkenaan','berlainan','berlalu','berlangsung','berlebihan','bermacam','bermacam-macam', - 'bermaksud','bermula','bersama','bersama-sama','bersiap','bersiap-siap','bertanya', - 'bertanya-tanya','berturut','berturut-turut','bertutur','berujar','berupa','besar', - 'betul','betulkah','biasa','biasanya','bila','bilakah','bisa','bisakah','boleh','bolehkah', - 'bolehlah','buat','bukan','bukankah','bukanlah','bukannya','bulan','bung','c','cara', - 'caranya','cukup','cukupkah','cukuplah','cuma','d','dahulu','dalam','dan','dapat','dari', - 'daripada','datang','dekat','demi','demikian','demikianlah','dengan','depan','di','dia', - 'diakhiri','diakhirinya','dialah','diantara','diantaranya','diberi','diberikan','diberikannya', - 'dibuat','dibuatnya','didapat','didatangkan','digunakan','diibaratkan','diibaratkannya', - 'diingat','diingatkan','diinginkan','dijawab','dijelaskan','dijelaskannya','dikarenakan', - 'dikatakan','dikatakannya','dikerjakan','diketahui','diketahuinya','dikira','dilakukan', - 'dilalui','dilihat','dimaksud','dimaksudkan','dimaksudkannya','dimaksudnya','diminta', - 'dimintai','dimisalkan','dimulai','dimulailah','dimulainya','dimungkinkan','dini','dipastikan', - 'diperbuat','diperbuatnya','dipergunakan','diperkirakan','diperlihatkan','diperlukan', - 'diperlukannya','dipersoalkan','dipertanyakan','dipunyai','diri','dirinya','disampaikan', - 'disebut','disebutkan','disebutkannya','disini','disinilah','ditambahkan','ditandaskan', - 'ditanya','ditanyai','ditanyakan','ditegaskan','ditujukan','ditunjuk','ditunjuki','ditunjukkan', - 'ditunjukkannya','ditunjuknya','dituturkan','dituturkannya','diucapkan','diucapkannya', - 'diungkapkan','dong','dua','dulu','e','empat','enak','enggak','enggaknya','entah','entahlah', - 'f','g','guna','gunakan','h','hadap','hai','hal','halo','hallo','hampir','hanya','hanyalah', - 'hari','harus','haruslah','harusnya','helo','hello','hendak','hendaklah','hendaknya','hingga', - 'i','ia','ialah','ibarat','ibaratkan','ibaratnya','ibu','ikut','ingat','ingat-ingat','ingin', - 'inginkah','inginkan','ini','inikah','inilah','itu','itukah','itulah','j','jadi','jadilah', - 'jadinya','jangan','jangankan','janganlah','jauh','jawab','jawaban','jawabnya','jelas', - 'jelaskan','jelaslah','jelasnya','jika','jikalau','juga','jumlah','jumlahnya','justru', - 'k','kadar','kala','kalau','kalaulah','kalaupun','kali','kalian','kami','kamilah','kamu', - 'kamulah','kan','kapan','kapankah','kapanpun','karena','karenanya','kasus','kata','katakan', - 'katakanlah','katanya','ke','keadaan','kebetulan','kecil','kedua','keduanya','keinginan', - 'kelamaan','kelihatan','kelihatannya','kelima','keluar','kembali','kemudian','kemungkinan', - 'kemungkinannya','kena','kenapa','kepada','kepadanya','kerja','kesampaian','keseluruhan', - 'keseluruhannya','keterlaluan','ketika','khusus','khususnya','kini','kinilah','kira', - 'kira-kira','kiranya','kita','kitalah','kok','kurang','l','lagi','lagian','lah','lain', - 'lainnya','laku','lalu','lama','lamanya','langsung','lanjut','lanjutnya','lebih','lewat', - 'lihat','lima','luar','m','macam','maka','makanya','makin','maksud','malah','malahan', - 'mampu','mampukah','mana','manakala','manalagi','masa','masalah','masalahnya','masih', - 'masihkah','masing','masing-masing','masuk','mata','mau','maupun','melainkan','melakukan', - 'melalui','melihat','melihatnya','memang','memastikan','memberi','memberikan','membuat', - 'memerlukan','memihak','meminta','memintakan','memisalkan','memperbuat','mempergunakan', - 'memperkirakan','memperlihatkan','mempersiapkan','mempersoalkan','mempertanyakan','mempunyai', - 'memulai','memungkinkan','menaiki','menambahkan','menandaskan','menanti','menanti-nanti', - 'menantikan','menanya','menanyai','menanyakan','mendapat','mendapatkan','mendatang','mendatangi', - 'mendatangkan','menegaskan','mengakhiri','mengapa','mengatakan','mengatakannya','mengenai', - 'mengerjakan','mengetahui','menggunakan','menghendaki','mengibaratkan','mengibaratkannya', - 'mengingat','mengingatkan','menginginkan','mengira','mengucapkan','mengucapkannya','mengungkapkan', - 'menjadi','menjawab','menjelaskan','menuju','menunjuk','menunjuki','menunjukkan','menunjuknya', - 'menurut','menuturkan','menyampaikan','menyangkut','menyatakan','menyebutkan','menyeluruh', - 'menyiapkan','merasa','mereka','merekalah','merupakan','meski','meskipun','meyakini','meyakinkan', - 'minta','mirip','misal','misalkan','misalnya','mohon','mula','mulai','mulailah','mulanya','mungkin', - 'mungkinkah','n','nah','naik','namun','nanti','nantinya','nya','nyaris','nyata','nyatanya', - 'o','oleh','olehnya','orang','p','pada','padahal','padanya','pak','paling','panjang','pantas', - 'para','pasti','pastilah','penting','pentingnya','per','percuma','perlu','perlukah','perlunya', - 'pernah','persoalan','pertama','pertama-tama','pertanyaan','pertanyakan','pihak','pihaknya', - 'pukul','pula','pun','punya','q','r','rasa','rasanya','rupa','rupanya','s','saat','saatnya','saja', - 'sajalah','salam','saling','sama','sama-sama','sambil','sampai','sampai-sampai','sampaikan','sana', - 'sangat','sangatlah','sangkut','satu','saya','sayalah','se','sebab','sebabnya','sebagai', - 'sebagaimana','sebagainya','sebagian','sebaik','sebaik-baiknya','sebaiknya','sebaliknya', - 'sebanyak','sebegini','sebegitu','sebelum','sebelumnya','sebenarnya','seberapa','sebesar', - 'sebetulnya','sebisanya','sebuah','sebut','sebutlah','sebutnya','secara','secukupnya','sedang', - 'sedangkan','sedemikian','sedikit','sedikitnya','seenaknya','segala','segalanya','segera', - 'seharusnya','sehingga','seingat','sejak','sejauh','sejenak','sejumlah','sekadar','sekadarnya', - 'sekali','sekali-kali','sekalian','sekaligus','sekalipun','sekarang','sekaranglah','sekecil', - 'seketika','sekiranya','sekitar','sekitarnya','sekurang-kurangnya','sekurangnya','sela','selain', - 'selaku','selalu','selama','selama-lamanya','selamanya','selanjutnya','seluruh','seluruhnya', - 'semacam','semakin','semampu','semampunya','semasa','semasih','semata','semata-mata','semaunya', - 'sementara','semisal','semisalnya','sempat','semua','semuanya','semula','sendiri','sendirian', - 'sendirinya','seolah','seolah-olah','seorang','sepanjang','sepantasnya','sepantasnyalah', - 'seperlunya','seperti','sepertinya','sepihak','sering','seringnya','serta','serupa','sesaat', - 'sesama','sesampai','sesegera','sesekali','seseorang','sesuatu','sesuatunya','sesudah', - 'sesudahnya','setelah','setempat','setengah','seterusnya','setiap','setiba','setibanya', - 'setidak-tidaknya','setidaknya','setinggi','seusai','sewaktu','siap','siapa','siapakah', - 'siapapun','sini','sinilah','soal','soalnya','suatu','sudah','sudahkah','sudahlah','supaya', - 't','tadi','tadinya','tahu','tak','tambah','tambahnya','tampak','tampaknya','tandas','tandasnya', - 'tanpa','tanya','tanyakan','tanyanya','tapi','tegas','tegasnya','telah','tempat','tentang','tentu', - 'tentulah','tentunya','tepat','terakhir','terasa','terbanyak','terdahulu','terdapat','terdiri', - 'terhadap','terhadapnya','teringat','teringat-ingat','terjadi','terjadilah','terjadinya','terkira', - 'terlalu','terlebih','terlihat','termasuk','ternyata','tersampaikan','tersebut','tersebutlah', - 'tertentu','tertuju','terus','terutama','tetap','tetapi','tiap','tiba','tiba-tiba','tidak', - 'tidakkah','tidaklah','tiga','toh','tuju','tunjuk','turut','tutur','tuturnya','u','ucap','ucapnya', - 'ujar','ujarnya','umumnya','ungkap','ungkapnya','untuk','usah','usai','v','w','waduh','wah','wahai', - 'waktunya','walau','walaupun','wong','x','y','ya','yaitu','yakin','yakni','yang','z'] - + @cached(cache=LRUCache(maxsize=8)) + def get_prod_stop_word_dictionary(self): + stopWords = self.get_stop_words() + return ArrayDictionary(stopWords) + def get_stop_words(self): + current_dir = os.path.dirname(os.path.realpath(__file__)) + dictionaryFile = current_dir + '/data/stopword_tala_2003.txt' + if not os.path.isfile(dictionaryFile): + raise RuntimeError('Stopword file is missing. It seems that your installation is corrupted.') + text = '' + with open(dictionaryFile, 'r') as f: + text = f.read() + return text.split('\n') \ No newline at end of file diff --git a/src/Sastrawi/StopWordRemover/data/stopword_tala_2003.txt b/src/Sastrawi/StopWordRemover/data/stopword_tala_2003.txt new file mode 100644 index 0000000..bf88a45 --- /dev/null +++ b/src/Sastrawi/StopWordRemover/data/stopword_tala_2003.txt @@ -0,0 +1,758 @@ +ada +adalah +adanya +adapun +agak +agaknya +agar +akan +akankah +akhir +akhiri +akhirnya +aku +akulah +amat +amatlah +anda +andalah +antar +antara +antaranya +apa +apaan +apabila +apakah +apalagi +apatah +artinya +asal +asalkan +atas +atau +ataukah +ataupun +awal +awalnya +bagai +bagaikan +bagaimana +bagaimanakah +bagaimanapun +bagi +bagian +bahkan +bahwa +bahwasanya +baik +bakal +bakalan +balik +banyak +bapak +baru +bawah +beberapa +begini +beginian +beginikah +beginilah +begitu +begitukah +begitulah +begitupun +bekerja +belakang +belakangan +belum +belumlah +benar +benarkah +benarlah +berada +berakhir +berakhirlah +berakhirnya +berapa +berapakah +berapalah +berapapun +berarti +berawal +berbagai +berdatangan +beri +berikan +berikut +berikutnya +berjumlah +berkali-kali +berkata +berkehendak +berkeinginan +berkenaan +berlainan +berlalu +berlangsung +berlebihan +bermacam +bermacam-macam +bermaksud +bermula +bersama +bersama-sama +bersiap +bersiap-siap +bertanya +bertanya-tanya +berturut +berturut-turut +bertutur +berujar +berupa +besar +betul +betulkah +biasa +biasanya +bila +bilakah +bisa +bisakah +boleh +bolehkah +bolehlah +buat +bukan +bukankah +bukanlah +bukannya +bulan +bung +cara +caranya +cukup +cukupkah +cukuplah +cuma +dahulu +dalam +dan +dapat +dari +daripada +datang +dekat +demi +demikian +demikianlah +dengan +depan +di +dia +diakhiri +diakhirinya +dialah +diantara +diantaranya +diberi +diberikan +diberikannya +dibuat +dibuatnya +didapat +didatangkan +digunakan +diibaratkan +diibaratkannya +diingat +diingatkan +diinginkan +dijawab +dijelaskan +dijelaskannya +dikarenakan +dikatakan +dikatakannya +dikerjakan +diketahui +diketahuinya +dikira +dilakukan +dilalui +dilihat +dimaksud +dimaksudkan +dimaksudkannya +dimaksudnya +diminta +dimintai +dimisalkan +dimulai +dimulailah +dimulainya +dimungkinkan +dini +dipastikan +diperbuat +diperbuatnya +dipergunakan +diperkirakan +diperlihatkan +diperlukan +diperlukannya +dipersoalkan +dipertanyakan +dipunyai +diri +dirinya +disampaikan +disebut +disebutkan +disebutkannya +disini +disinilah +ditambahkan +ditandaskan +ditanya +ditanyai +ditanyakan +ditegaskan +ditujukan +ditunjuk +ditunjuki +ditunjukkan +ditunjukkannya +ditunjuknya +dituturkan +dituturkannya +diucapkan +diucapkannya +diungkapkan +dong +dua +dulu +empat +enggak +enggaknya +entah +entahlah +guna +gunakan +hal +hampir +hanya +hanyalah +hari +harus +haruslah +harusnya +hendak +hendaklah +hendaknya +hingga +ia +ialah +ibarat +ibaratkan +ibaratnya +ibu +ikut +ingat +ingat-ingat +ingin +inginkah +inginkan +ini +inikah +inilah +itu +itukah +itulah +jadi +jadilah +jadinya +jangan +jangankan +janganlah +jauh +jawab +jawaban +jawabnya +jelas +jelaskan +jelaslah +jelasnya +jika +jikalau +juga +jumlah +jumlahnya +justru +kala +kalau +kalaulah +kalaupun +kalian +kami +kamilah +kamu +kamulah +kan +kapan +kapankah +kapanpun +karena +karenanya +kasus +kata +katakan +katakanlah +katanya +ke +keadaan +kebetulan +kecil +kedua +keduanya +keinginan +kelamaan +kelihatan +kelihatannya +kelima +keluar +kembali +kemudian +kemungkinan +kemungkinannya +kenapa +kepada +kepadanya +kesampaian +keseluruhan +keseluruhannya +keterlaluan +ketika +khususnya +kini +kinilah +kira +kira-kira +kiranya +kita +kitalah +kok +kurang +lagi +lagian +lah +lain +lainnya +lalu +lama +lamanya +lanjut +lanjutnya +lebih +lewat +lima +luar +macam +maka +makanya +makin +malah +malahan +mampu +mampukah +mana +manakala +manalagi +masa +masalah +masalahnya +masih +masihkah +masing +masing-masing +mau +maupun +melainkan +melakukan +melalui +melihat +melihatnya +memang +memastikan +memberi +memberikan +membuat +memerlukan +memihak +meminta +memintakan +memisalkan +memperbuat +mempergunakan +memperkirakan +memperlihatkan +mempersiapkan +mempersoalkan +mempertanyakan +mempunyai +memulai +memungkinkan +menaiki +menambahkan +menandaskan +menanti +menanti-nanti +menantikan +menanya +menanyai +menanyakan +mendapat +mendapatkan +mendatang +mendatangi +mendatangkan +menegaskan +mengakhiri +mengapa +mengatakan +mengatakannya +mengenai +mengerjakan +mengetahui +menggunakan +menghendaki +mengibaratkan +mengibaratkannya +mengingat +mengingatkan +menginginkan +mengira +mengucapkan +mengucapkannya +mengungkapkan +menjadi +menjawab +menjelaskan +menuju +menunjuk +menunjuki +menunjukkan +menunjuknya +menurut +menuturkan +menyampaikan +menyangkut +menyatakan +menyebutkan +menyeluruh +menyiapkan +merasa +mereka +merekalah +merupakan +meski +meskipun +meyakini +meyakinkan +minta +mirip +misal +misalkan +misalnya +mula +mulai +mulailah +mulanya +mungkin +mungkinkah +nah +naik +namun +nanti +nantinya +nyaris +nyatanya +oleh +olehnya +pada +padahal +padanya +pak +paling +panjang +pantas +para +pasti +pastilah +penting +pentingnya +per +percuma +perlu +perlukah +perlunya +pernah +persoalan +pertama +pertama-tama +pertanyaan +pertanyakan +pihak +pihaknya +pukul +pula +pun +punya +rasa +rasanya +rata +rupanya +saat +saatnya +saja +sajalah +saling +sama +sama-sama +sambil +sampai +sampai-sampai +sampaikan +sana +sangat +sangatlah +satu +saya +sayalah +se +sebab +sebabnya +sebagai +sebagaimana +sebagainya +sebagian +sebaik +sebaik-baiknya +sebaiknya +sebaliknya +sebanyak +sebegini +sebegitu +sebelum +sebelumnya +sebenarnya +seberapa +sebesar +sebetulnya +sebisanya +sebuah +sebut +sebutlah +sebutnya +secara +secukupnya +sedang +sedangkan +sedemikian +sedikit +sedikitnya +seenaknya +segala +segalanya +segera +seharusnya +sehingga +seingat +sejak +sejauh +sejenak +sejumlah +sekadar +sekadarnya +sekali +sekali-kali +sekalian +sekaligus +sekalipun +sekarang +sekarang +sekecil +seketika +sekiranya +sekitar +sekitarnya +sekurang-kurangnya +sekurangnya +sela +selain +selaku +selalu +selama +selama-lamanya +selamanya +selanjutnya +seluruh +seluruhnya +semacam +semakin +semampu +semampunya +semasa +semasih +semata +semata-mata +semaunya +sementara +semisal +semisalnya +sempat +semua +semuanya +semula +sendiri +sendirian +sendirinya +seolah +seolah-olah +seorang +sepanjang +sepantasnya +sepantasnyalah +seperlunya +seperti +sepertinya +sepihak +sering +seringnya +serta +serupa +sesaat +sesama +sesampai +sesegera +sesekali +seseorang +sesuatu +sesuatunya +sesudah +sesudahnya +setelah +setempat +setengah +seterusnya +setiap +setiba +setibanya +setidak-tidaknya +setidaknya +setinggi +seusai +sewaktu +siap +siapa +siapakah +siapapun +sini +sinilah +soal +soalnya +suatu +sudah +sudahkah +sudahlah +supaya +tadi +tadinya +tahu +tahun +tak +tambah +tambahnya +tampak +tampaknya +tandas +tandasnya +tanpa +tanya +tanyakan +tanyanya +tapi +tegas +tegasnya +telah +tempat +tengah +tentang +tentu +tentulah +tentunya +tepat +terakhir +terasa +terbanyak +terdahulu +terdapat +terdiri +terhadap +terhadapnya +teringat +teringat-ingat +terjadi +terjadilah +terjadinya +terkira +terlalu +terlebih +terlihat +termasuk +ternyata +tersampaikan +tersebut +tersebutlah +tertentu +tertuju +terus +terutama +tetap +tetapi +tiap +tiba +tiba-tiba +tidak +tidakkah +tidaklah +tiga +tinggi +toh +tunjuk +turut +tutur +tuturnya +ucap +ucapnya +ujar +ujarnya +umum +umumnya +ungkap +ungkapnya +untuk +usah +usai +waduh +wah +wahai +waktu +waktunya +walau +walaupun +wong +yaitu +yakin +yakni +yang \ No newline at end of file diff --git a/tests/FunctionalTests/Stemmer/stemmer_test.py b/tests/FunctionalTests/Stemmer/stemmer_test.py index c1f56ed..8609fb7 100644 --- a/tests/FunctionalTests/Stemmer/stemmer_test.py +++ b/tests/FunctionalTests/Stemmer/stemmer_test.py @@ -328,8 +328,8 @@ def get_test_data(self): data.append(['menahan', 'tahan']) # test stem multiple sentences - multipleSentence1 = 'Cinta telah bertebaran.Keduanya saling mencintai.'; - multipleSentence2 = "(Cinta telah bertebaran)\n\n\n\nKeduanya saling mencintai."; + multipleSentence1 = 'Cinta telah bertebaran.Keduanya saling mencintai.' + multipleSentence2 = "(Cinta telah bertebaran)\n\n\n\nKeduanya saling mencintai." data.append([multipleSentence1, 'cinta telah tebar dua saling cinta']) data.append([multipleSentence2, 'cinta telah tebar dua saling cinta']) diff --git a/tests/UnitTests/Dictionary/array_dictionary_test.py b/tests/UnitTests/Dictionary/array_dictionary_test.py index 57d72fc..42c5580 100644 --- a/tests/UnitTests/Dictionary/array_dictionary_test.py +++ b/tests/UnitTests/Dictionary/array_dictionary_test.py @@ -36,5 +36,22 @@ def test_constructor_preserve_words(self): self.assertTrue(dictionary.contains('word1')) self.assertTrue(dictionary.contains('word2')) + # Test ArrayDictionary dengan tipe data dict + # @author Mufid Jamaluddin + def test_dict_param(self): + dictionary = ArrayDictionary({'word1':'word1', 'word2':'word2'}) + self.assertTrue(dictionary.contains('word1')) + self.assertTrue(dictionary.contains('word2')) + self.assertFalse(dictionary.contains('word3')) + self.assertEqual(2, dictionary.count()) + dictionary.add('word3') + dictionary.add(' ') + self.assertTrue(dictionary.contains('word3')) + self.assertEqual(3, dictionary.count()) + + def test_non_dict_list(self): + dictionary = ArrayDictionary('$$%&**&(^&') + self.assertEqual(0, dictionary.count()) + if __name__ == '__main__': unittest.main() diff --git a/tests/UnitTests/Stemmer/stemmer_factory_test.py b/tests/UnitTests/Stemmer/stemmer_factory_test.py index 146df28..9df96b7 100644 --- a/tests/UnitTests/Stemmer/stemmer_factory_test.py +++ b/tests/UnitTests/Stemmer/stemmer_factory_test.py @@ -1,4 +1,5 @@ import unittest +import time from Sastrawi.Stemmer.StemmerFactory import StemmerFactory from Sastrawi.Stemmer.Stemmer import Stemmer @@ -23,9 +24,55 @@ def test_fungsional(self): if output != expected: raise AssertionError(str.format('output is {} instead of {}', output, expected)) + # Test Waktu Stemming < 3 detik + # @author Mufid Jamaluddin + def test_execution_time(self): + start = time.time() + sentence = 'Rakyat memenuHi halaMan geDung DPR unTuk menyuarakan isi hatinya. Saat Itu, situasi sangat genting sekali. Terjadi kerusuhan yang mengiringi pergerakan mahasiswa yang memperjuangkan reformasi.' + + factory = StemmerFactory() + stemmer = factory.create_stemmer() + stemmer.stem(sentence) + + end = time.time() + + execution_time = end - start + self.assertTrue(execution_time < 3) + def test_getWordsFromFile(self): factory = StemmerFactory() factory.get_words_from_file() + # Test Stemming per Kata + # @author Mufid Jamaluddin + def test_word_stemming(self): + factory = StemmerFactory() + stemmer = factory.create_stemmer() + self.assertEqual('besar', stemmer.stem('terbesar')) + self.assertEqual('abai', stemmer.stem('diabaikan')) + + # Test Stemming dengan isDev=True (No Cache) + # @author Mufid Jamaluddin + def test_word_stemmingdev(self): + factory = StemmerFactory() + stemmer = factory.create_stemmer(isDev=True) + self.assertEqual('besar', stemmer.stem('terbesar')) + self.assertEqual('abai', stemmer.stem('diabaikan')) + + # Test Stemming dengan list tokens + # @author Mufid Jamaluddin + def test_tokens_stemming(self): + factory = StemmerFactory() + stemmer = factory.create_stemmer() + tokens = ['perekonomian', '', 'indonesia', 'sedang', ' ', 'dalam', 'pertumbuhan' ,'yang', 'membanggakan'] + clean_tokens = stemmer.stem_tokens(tokens) + self.assertEqual('ekonomi', clean_tokens[0]) + self.assertEqual('indonesia', clean_tokens[1]) + self.assertEqual('sedang', clean_tokens[2]) + self.assertEqual('dalam', clean_tokens[3]) + self.assertEqual('tumbuh', clean_tokens[4]) + self.assertEqual('yang', clean_tokens[5]) + self.assertEqual('bangga', clean_tokens[6]) + if __name__ == '__main__': unittest.main() diff --git a/tests/UnitTests/StopWordRemover/stop_word_remover_factory_test.py b/tests/UnitTests/StopWordRemover/stop_word_remover_factory_test.py index 5f758f8..8c82336 100644 --- a/tests/UnitTests/StopWordRemover/stop_word_remover_factory_test.py +++ b/tests/UnitTests/StopWordRemover/stop_word_remover_factory_test.py @@ -1,4 +1,5 @@ import unittest +import time from Sastrawi.StopWordRemover.StopWordRemoverFactory import StopWordRemoverFactory from Sastrawi.StopWordRemover.StopWordRemover import StopWordRemover @@ -9,6 +10,33 @@ def setUp(self): def test_createStopWordRemover(self): self.assertIsInstance(self.factory.create_stop_word_remover(), StopWordRemover) + + def test_stopwordRemoval(self): + sremover = self.factory.create_stop_word_remover() + self.assertEqual('pergi sekolah', sremover.remove('pergi ke sekolah yang')) + self.assertEqual('makan rumah', sremover.remove('makan di rumah yang')) + + def test_tokens_stopwordRemoval(self): + tokens = ['pergi', 'ke', 'sekolah', 'yang', 'bagus', 'adalah', 'impian'] + sremover = self.factory.create_stop_word_remover() + clean_tokens = sremover.remove_tokens(tokens) + text = ' '.join(clean_tokens) + self.assertEquals('pergi sekolah bagus impian', text) + self.assertEqual('pergi', clean_tokens[0]) + self.assertEqual('sekolah', clean_tokens[1]) + self.assertEqual('bagus', clean_tokens[2]) + self.assertEqual('impian', clean_tokens[3]) + + def test_execution_time(self): + start = time.time() + sentence = 'Rakyat memenuHi halaMan geDung DPR unTuk menyuarakan isi hatinya. Saat Itu, situasi sangat genting sekali. Terjadi kerusuhan yang mengiringi pergerakan mahasiswa yang memperjuangkan reformasi.' + sremover = self.factory.create_stop_word_remover() + sremover.remove(sentence) + end = time.time() + # print(execution_time) + execution_time = end - start + + self.assertTrue(execution_time < 1) if __name__ == '__main__': unittest.main()