def test_word_probability(self): ''' test the word probability calculation ''' spell = SpellChecker() # if the default load changes so will this... num = spell.word_frequency['the'] denom = spell.word_frequency.total_words self.assertEqual(spell.word_probability('the'), num / denom)
def demo_spellchecker(): """演示如何使用spellchecker库 官方介绍文档 pyspellchecker · PyPI: https://pypi.org/project/pyspellchecker/ 190909周一15:58,from 陈坤泽 """ # 1 创建对象 # 可以设置语言、大小写敏感、拼写检查的最大距离 # 默认'en'英语,大小写不敏感 spell = SpellChecker() # 如果是英语,SpellChecker会自动加载语言包site-packages\spellchecker\resources\en.json.gz,大概12万个词汇,包括词频权重 d = spell.word_frequency # 这里的d是WordFrequency对象,其底层用了Counter类进行数据存储 dprint(d.unique_words, d.total_words) # 词汇数,权重总和 # 2 修改词频表 spell.word_frequency dprint(d['ckz']) # 不存在的词汇直接输出0 d.add('ckz') # 可以添加ckz词汇的一次词频 d.load_words(['ckz', 'ckz', 'lyb']) # 可以批量添加词汇 dprint(d['ckz'], d['lyb']) # d['ckz']=3 d['lyb']=1 d.load_words(['ckz'] * 100 + ['lyb'] * 500) # 可以用这种技巧进行大权重的添加 dprint(d['ckz'], d['lyb']) # d['ckz']=103 d['lyb']=501 # 同理,去除也有remove和remove_words两种方法 d.remove('ckz') # d.remove_words(['ckz', 'lyb']) # 不过注意不能删除已经不存在的key('ckz'),否则会报KeyError dprint(d['ckz'], d['lyb']) # d['ckz']=0 d['lyb']=501 # remove是完全去除单词,如果只是要减权重可以访问底层的_dictionary对象操作 d._dictionary['lyb'] -= 100 # 当然不太建议直接访问下划线开头的成员变量~~ dprint(d['lyb']) # ['lyb']=401 # 还可以按阈值删除词频不超过设置阈值的词汇 d.remove_by_threshold(5) # 3 spell的基本功能 # (1)用unknown可以找到可能拼写错误的单词,再用correction可以获得最佳修改意见 misspelled = spell.unknown(['something', 'is', 'hapenning', 'here']) dprint(misspelled) # misspelled<set>={'hapenning'} for word in misspelled: # Get the one `most likely` answer dprint(spell.correction(word)) # <str>='happening' # Get a list of `likely` options dprint(spell.candidates( word)) # <set>={'henning', 'happening', 'penning'} # 注意默认的spell不区分大小写,如果词库存储了100次'ckz' # 此时判断任意大小写形式组合的'CKZ'都是返回原值 # 例如 spell.correction('ckZ') => 'ckZ' # (2)可以通过修改spell.word_frequency影响correction的计算结果 dprint(d['henning'], d['happening'], d['penning']) # d['henning']<int>=53 d['happening']<int>=4538 d['penning']<int>=23 d._dictionary['henning'] += 10000 dprint(spell.correction('hapenning')) # <str>='henning' # (3)词汇在整个字典里占的权重 dprint(spell.word_probability('henning')) # <float>=0.0001040741914298211
def correctDLWord(self, misspelled): spellDL = SpellChecker(language=None) spellDL.word_frequency.load_text_file(self.text_file_path) #spellDL.export("DL_dictionary.gz", gzipped = True) misspelled_lower = misspelled.lower() if misspelled_lower in spellDL: return (misspelled, 1.0) else: correct = spellDL.correction(misspelled_lower) prob = spellDL.word_probability(misspelled_lower, total_words=1) return (correct, prob)
def correctListWord(self, misspelled, fig_text): if fig_text != []: spellList = SpellChecker(language=None) # load default dictionary spellList.word_frequency.load_words(fig_text) misspelled_lower = misspelled.lower() if misspelled_lower in spellList: return (misspelled, 1.0) else: correct = spellList.correction(misspelled_lower) prob = spellList.word_probability(misspelled_lower, total_words=1) return (correct, prob) else: return (None, 0.0)
def xor_strings(self): puntaje_final_strings = [] file_read = open(self.file_name, "r") out = open("salida", "w") spell = SpellChecker() for line in file_read: #print(line) cadena_hex = line.rstrip("\n") cadena = cadena_hex.decode("hex") print(cadena) res = '' puntaje_final = 0 puntaje_final = [] for i in range(256): for j in cadena: res_byte = ord(j) ^ i res += chr(res_byte) puntaje_actual = analiza_frecuencia(res) puntaje_final.append((puntaje_actual, res, i)) res = '' ult = heapq.nlargest(10, puntaje_final) puntaje_actual = 0 for i in range(10): palabras = ult[i][1].split(' ') mejor_palabra = spell.known(palabras) if (mejor_palabra): for palabra in mejor_palabra: puntaje_actual += spell.word_probability(palabra) puntaje_final_strings.append( (puntaje_actual, ult[i][1], ult[i][2])) ult = heapq.nlargest(1, puntaje_final_strings) print(ult[0][1]) file_read.close() out.close()
class Corrector: def __init__(self, lenguaje, diccionario=None, distancia=2, tokenizador=None): """ Constructor por defecto de la clase `Corrector`. Esta clase se \ encarga de realizar corrección ortográfica sobre textos. :param lenguaje: Lenguaje de los textos a los que se les va a \ aplicar corrección ortográfica. Para mayor información, consultar \ la sección de \ :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`. :type lenguaje: str :param diccionario: Diccionario (o string con ubicación del archivo \ JSON que lo contiene), o lista que permite modificar y agregar \ palabras. Si es una lista, contiene las palabras que serán \ consideradas como válidas o correctas. \ Si es un diccionario, las llaves del diccionario son las palabras \ que serán consideradas como válidas o correctas, y los valores \ del diccionario son las frecuencias de cada palabra en el \ diccionario. Las frecuencias son utilizadas como criterio de \ desempate, cuando una palabra incorrecta tiene más de una palabra \ candidata para la corrección. Si se deja este \ parámetro como `None`, se cargará el diccionario por defecto que \ trae la librería `spellchecker` para el lenguaje determinado. :type diccionario: dict, list, str, opcional :param distancia: Máxima distancia de \ Levenshtein que puede haber entre una palabra incorrecta (o no \ reconocida) y las palabras del diccionario para determinar si \ hay palabras candidatas para realizar la corrección. \ Valor por defecto `2`. :type distancia: int :param tokenizador: Objeto encargado de la tokenización y \ detokenización de textos. Si el valor es `None`, se cargará por \ defecto una instancia de la clase `TokenizadorNLTK`. Valor por \ defecto `None` :type tokenizador: object, opcional """ # Definir lenguaje del corrector ortográfico self.establecer_lenguaje(lenguaje) # Inicializar corrector self.iniciar_corrector(diccionario) self.establecer_distancia(distancia) self.tokenizador = (TokenizadorNLTK() if tokenizador is None else tokenizador) def establecer_lenguaje(self, lenguaje): """ Permite definir o cambiar el lenguaje de los textos sobre los cuales \ van a aplicarse el objeto de la clase `Corrector`. :param lenguaje: Lenguaje de los textos a los que se les va a \ aplicar corrección ortográfica. Para mayor información, consultar \ la sección de \ :ref:`Lenguajes soportados <seccion_lenguajes_soportados>`. :type lenguaje: str """ self.lenguaje = definir_lenguaje(lenguaje) def iniciar_corrector(self, diccionario): """ Inicializa el objeto de la clase `SpellChecker` de la librería \ spellchecker, para el lenguaje definido previamente, y lo asigna al \ atributo "corrector" del objeto de clase `Corrector`. :param diccionario: Diccionario (o string con ubicación del archivo \ JSON que lo contiene), o lista que permite modificar y agregar \ palabras. Si es una lista, contiene las palabras que serán \ consideradas como válidas o correctas. \ Si es un diccionario, las llaves del diccionario son las palabras \ que serán consideradas como válidas o correctas, y los valores \ del diccionario son las frecuencias de cada palabra en el \ diccionario. Las frecuencias son utilizadas como criterio de \ desempate, cuando una palabra incorrecta tiene más de una palabra \ candidata para la corrección. Si se deja este \ parámetro como `None`, se cargará el diccionario por defecto que \ trae la librería `spellchecker` para el lenguaje determinado. :type diccionario: dict, list, str, opcional """ self.corrector = None if self.lenguaje is not None: if isinstance(diccionario, str): self.corrector = SpellChecker(local_dictionary=diccionario) elif type(diccionario) in [dict, list]: self.corrector = SpellChecker(language=self.lenguaje) self.actualizar_diccionario(diccionario) else: self.corrector = SpellChecker(language=self.lenguaje) def establecer_distancia(self, distancia): """ Establece la distancia máxima que utilizará el algoritmo de corrección\ de ortografía para determinar si hay palabras candidatas para \ corregir una palabra incorrecta o no reconocida. :param distancia: Máxima distancia de \ Levenshtein que puede haber entre una palabra incorrecta (o no \ reconocida) y las palabras del diccionario para determinar si \ hay palabras candidatas para realizar la corrección. \ Valor por defecto `2`. :type distancia: int """ if self.corrector is not None: self.corrector.distance = distancia def actualizar_diccionario(self, diccionario): """ Actualiza el diccionario que contiene las palabras válidas o \ reconocidas disponibles para realizar la corrección ortográfica. Las \ palabras contenidas en el argumento `diccionario` de esta función \ serán añadidas (o sus frecuencias serán actualizadas) en el \ diccionario que ya existe en el objeto de la clase `Corrector`. :param diccionario: Diccionario (o string con ubicación del archivo \ JSON que lo contiene), o lista que permite modificar y agregar \ palabras. Si es una lista, contiene las palabras que serán \ consideradas como válidas o correctas. \ Si es un diccionario, las llaves del diccionario son las palabras \ que serán consideradas como válidas o correctas, y los valores \ del diccionario son las frecuencias de cada palabra en el \ diccionario. Las frecuencias son utilizadas como criterio de \ desempate, cuando una palabra incorrecta tiene más de una palabra \ candidata para la corrección. Si se deja este \ parámetro como `None`, se cargará el diccionario por defecto que \ trae la librería `spellchecker` para el lenguaje determinado. :type diccionario: dict, list, str, opcional """ if isinstance(diccionario, str): diccionario = json.load(open(diccionario)) if isinstance(diccionario, list): diccionario = [palabra.lower() for palabra in diccionario] self.corrector.word_frequency.load_words(diccionario) elif isinstance(diccionario, dict): self.quitar_palabras(list(diccionario.keys())) for key in diccionario.keys(): self.corrector.word_frequency.load_words([key.lower()] * diccionario[key]) else: pass def quitar_palabras(self, palabras): """ Quita del diccionario del corrector una o más palabras \ proporcionadas en el argumento `palabras`, haciendo que estas ya no \ sean reconocidas como palabras válidas o correctas al momento de \ hacer corrección ortográfica. :param palabras: Palabra o lista de palabras que se \ desean quitar del diccionario del objeto de la clase `Corrector`, \ para que no sean reconocidas como correctas al momento de hacer \ la corrección ortográfica. :type palabras: str, list """ if isinstance(palabras, str): palabras = [palabras] # Quitar de la lista palabras que no estén en el diccionario palabras = [p for p in palabras if self.frecuencia_palabra(p) > 0] if len(palabras) > 0: self.corrector.word_frequency.remove_words(palabras) def agregar_palabras(self, palabras): """ Añade al diccionario del corrector una o más palabras proporcionadas \ en el argumento `palabras`, haciendo que estas sean reconocidas como \ palabras válidas o correctas al momento de hacer corrección \ ortográfica. :param palabras: Palabra o lista de palabras que se \ desean quitar del diccionario del objeto de la clase `Corrector`, \ para que no sean reconocidas como correctas al momento de hacer \ la corrección ortográfica. :type palabras: str, list """ if isinstance(palabras, str): palabras = [palabras] self.actualizar_diccionario(palabras) def palabras_conocidas(self, texto): """ A partir de un texto de entrada, devuelve un conjunto (objeto de \ clase `set` de Python) con las palabras del texto que se reconocen \ por estar presentes en el diccionario del corrector. :param texto: Texto para el que se desean hayar las palabras \ conocidas. :type texto: str :return: (set) Conjunto de palabras conocidas presentes en el texto \ de entrada. """ tokens = self.tokenizador.tokenizar(texto) return self.corrector.known(tokens) def palabras_desconocidas(self, texto): """ A partir de un texto de entrada, devuelve un conjunto (objeto de \ clase `set` de Python) con las palabras del texto que no están \ incluidas en el diccionario del corrector y por lo tanto no se \ reconocen. :param texto: Texto para el que se desean hallar las palabras \ desconocidas. :type texto: str :return: (set) Conjunto de palabras desconocidas presentes en el \ texto de entrada. """ tokens = self.tokenizador.tokenizar(texto) return self.corrector.unknown(tokens) def palabras_candidatas(self, palabra): """ Para una palabra de entrada, retorna un conjunto de palabras que \ podrían ser utilizadas para corregirla. Si la palabra de entrada es \ correcta (está dentro del diccionario del corrector) o no tienen \ ninguna palabra candidata con una distancia menor o igual a la \ establecida en el parámetro `distancia` de la clase `Corrector`, la \ función devolverá la misma palabra de entrada. :param palabra: Palabra para la que se quieren conocer palabras \ candidatas para su corrección ortográfica. :type palabra: str :return: (set) Conjunto de palabras candidatas para corregir la \ palabra de entrada. """ return self.corrector.candidates(palabra) def frecuencia_palabra(self, palabra): """ Para una palabra de entrada, devuelve la frecuencia de la misma, de \ acuerdo al diccionario del corrector. Si la palabra es desconocida \ (no se encuentra en el diccionario), la frecuencia retornada será de \ cero. :param palabra: Palabra para la cual se desea conocer la \ frecuencia de aparición en el diccionario del corrector. :type palabra: str :return: (int) Número mayor o igual a cero que indica la frecuencia \ de la palabra consultada en el diccionario del corrector. """ return self.corrector[palabra] def probabilidad_palabra(self, palabra): """ Para una palabra de entrada, devuelve la probabilidad de aparición \ entendida como su frecuencia sobre la suma de las \ frecuencias de todas las palabras disponibles, de acuerdo al \ diccionario del corrector. Si la palabra es desconocida (no se \ encuentra en el diccionario), la probabilidad retornada será de cero. :param palabra: Palabra para la cual se desea conocer la \ probabilidad de aparición en el diccionario del corrector. :type palabra: str :return: (float) Probabilidad, entre 0 y 1, de aparición de la \ palabra. """ return self.corrector.word_probability(palabra) def correccion_ortografia(self, texto, limpieza=False): """ Realiza corrección ortográfica sobre un texto de entrada, \ identificando las palabras que no están en el diccionario del \ corrector y cambiándolas por su candidata más frecuente o probable, \ siempre y cuando haya por lo menos una palabra candidata que cumpla \ con la máxima distancia de Levenshtein permitida. :param texto: Texto al cual se desea aplicar corrección \ ortográfica. :param limpieza: Define si se desea hacer una limpieza \ básica (aplicando la función `limpieza_basica` del módulo \ `limpieza`) al texto antes de aplicar la corrección ortográfica.\ Valor por defecto `False`. :type limpieza: bool, opcional :return: (str) Texto de entrada luego de la corrección ortográfica. """ if limpieza: # Limpieza básica del texto para que no afecte la corrección texto = limpieza_basica(texto, quitar_numeros=False) lista_palabras = self.tokenizador.tokenizar(texto) desconocidas = self.corrector.unknown(lista_palabras) texto_corregido = [ self.corrector.correction(p) if len(p) > 1 and p in desconocidas else p for p in lista_palabras ] return self.tokenizador.destokenizar(texto_corregido)
accepted = True if len(sentence) < 50 or len(sentence) > 300: accepted = False if not full_stop: accepted = False count += 1 return sentence sentence = generate_sentence(forwards_model, backwards_model, seed_word=u" analytic ") sentence = sentence[1:] words = sentence.split(' ') corrected_sentence = [] for word in words: if word == ' ': continue corrected_word = spell.correction(word) print('word = ', word, ' correction = ', corrected_word, ' probability = ', spell.word_probability(corrected_word)) print('candidates = ', spell.candidates(word)) if len(spell.known([corrected_word])) == 1 or word.isnumeric(): corrected_sentence.append(corrected_word) sentence = ' '.join(corrected_sentence) + '.' sentence = sentence[0].upper() + sentence[1:] sentence = sentence.replace(' i ', ' I ') print(sentence)
def check_spelling(self): # requires 'pyspellchecker' package of Python # for texts checks if they are spelled correctly # if low frequency of suggestion, manual intervention needed # manual entry will be stored and used for the next time # if ERROR is True, the next code will not be executed if self.ERROR == True: return langs = { 'en': 'english', 'fr': 'french', 'de': 'german', 'it': 'italian' } # provide a list of corrections corrections_list = [] corrected_data = [] # join all texts from self.data in one string # easier to later tokenize in a single step self.stdout.write('Spell checking ->\n') spell = SpellChecker(self.LNG) # get stop words for the given language stop_words = set(stopwords.words(langs[self.LNG])) # list of all tested words to avoid repetitions tested_words = {} i = 0 for row in self.DATA: i += 1 if i == 1000: self.stdout.write('1k') i = 0 text = row['text'] words = word_tokenize(text) # filter stop words words_filtered = [ w for w in words if w not in stop_words and len(w) > 1 ] # check spelling and correct # create set to be faster process with a shorter number of words words_filtered = set(words_filtered) words_unknown = spell.unknown(words_filtered) # this will replace previous input in self.DATA words_corrected = [] for word in words_filtered: if len(word) > 3: try: # if already corrected previously # this includes all those with low freq that are not unknown correction = SpellCorrection.objects.get( language=self.LNG, word=word) words_corrected.append(correction.correction) except: # if not we need to check for candidates, if unknown if word in words_unknown: if word in tested_words: # well, if already tested words_corrected.append(tested_words[word]) continue candidates = list(spell.candidates(word)) # if correction is equal to word well it means that correcting failed if len(candidates) == 1 and word == candidates[0]: corrections_list.append({ 'word': word, 'correction': ' '.join(candidates), 'prob': 'unknown' }) # if many candidates if len(candidates) > 1: corrections_list.append({ 'word': word, 'correction': ' '.join(candidates), 'prob': 'unknown' }) # for correction we take the most probable word words_corrected.append(candidates[0]) else: words_corrected.append(word) if self.ARG_MOST_PROBABLE == False and word not in words_unknown: # also calculate frequency of those words if word not in tested_words: prob = spell.word_probability(word) * 10e6 if prob < 10: corrections_list.append({ 'word': word, 'correction': word, 'prob': prob }) tested_words[word] = word # not correcting those shorter or equal to length 3 else: words_corrected.append(word) # now correct row in self.DATA corrected_row = { 'text': ' '.join(words_corrected), 'code': row['code'] } corrected_data.append(corrected_row) self.DATA = corrected_data # if arg is --most-probable True # we assign the most probable candidate if self.ARG_MOST_PROBABLE == True: return # if no corrections in corrections_list no need to go further if len(corrections_list) == 0: self.stdout.write( self.style.SUCCESS("SUCCESS: NO CORRECTIONS REQUIRED")) return # ask if admin wants to provide corrections in console else: self.stdout.write( self.style.WARNING("%d corrections required" % len(corrections_list))) provide_corrections = input( 'Do you want to provide spell corrections?\n') if provide_corrections == 'Y': for cor in corrections_list: self.stdout.write("Which is correct for %s: \n %s\n" % (cor['word'], cor['correction'])) cor_text = input() if cor_text == 'cpy': # keep the same word cor_text = cor['word'] elif cor_text == 'ign': # skip correction continue spell_cor_ser = { "language": self.LNG, "word": cor['word'], "correction": cor_text } if spell_cor_ser.is_valid(): spell_cor_ser.save() # if not most probable # we must write CSV file with recommended candidates # and those with low freqency self.stdout.write("Writing to CSV") path = os.path.join(BASE_DIR, 'DATA/exported/corrections.csv') with open(path, 'w') as f: # write header f.write("word;correction;prob\n") for e in corrections_list: f.write("{};{};{}\n".format(e['word'], e['correction'], e['prob'])) self.ERROR = True self.ERROR_TEXT = "SOME WORDS REQUIRE SPELL CHECK" return False
d_w = sep.join(d_w) return [d_w] s3 = [] for word in s2.split(' '): # Looping through all the words in the book. clean_word = re.sub('[^a-zA-Z]+', '', word).lower() if len(clean_word) > 0: # Dealing with words with hyphens if '-' in word[:-1]: s3 += double_word_splitter(word, '-') elif '_' in word[:-1]: s3 += double_word_splitter(word, '_') # Dealing with non-hyphen words else: if spell.word_probability(clean_word) <= wrong_word_prob_cutoff: s3 += get_most_probable_split(word) else: s3 += [word] else: s3 += [word] txt = ' '.join(s3) f = open(root_dir + filename[:-4] + '.txt', "w") f.write(txt) f.close() # %% Exporting to mp3 engine = pyttsx3.init()
def query_expansion_thesaurus(query_str): """ Params: - query_str: Original input query string Returns: - new_query: List of expanded query terms and weights [ (term, weight), ...] """ query_str = query_str.replace('AND', '').replace('"', '') query_terms = set([query_term.strip() for query_term in query_str.split(' ')]) term_weights = defaultdict(lambda: 0.0) new_query_terms = list(query_terms) ORIGINAL_TERM_WEIGHT = 1 SYNONYM_TERM_WEIGHT = 0.5 MISSPELLING_TERM_WEIGHT = 0.6 CONTEXT_TERM_WEIGHT = 0.7 for term in query_terms: term_weights[term] = ORIGINAL_TERM_WEIGHT # Add synonyms to query FRACTION_SYNONYMS = 0.35 synonyms = [] for term in query_terms: for syn in wordnet.synsets(term): num_synonyms = math.ceil(len(syn.lemmas()) * FRACTION_SYNONYMS) for l in syn.lemmas()[:num_synonyms]: for t in l.name().split("_"): synonyms.append(t) term_weights[t] = max(SYNONYM_TERM_WEIGHT, term_weights[t]) # Use original query context to find suitable synonyms context_syn = lesk(query_str, term) if context_syn is not None: for l in context_syn.lemmas(): for t in l.name().split("_"): synonyms.append(t) term_weights[t] = max(CONTEXT_TERM_WEIGHT, term_weights[t]) new_query_terms.extend(synonyms) # Add spelling corrections spell = SpellChecker() unknown_misspelled_terms = spell.unknown(query_terms) for term in unknown_misspelled_terms: new_query_terms.append(spell.correction(term)) # Add the most likely correct word known_misspelled_terms = spell.known(query_terms) for mispelled_term in known_misspelled_terms: corrected_terms = spell.known(spell.edit_distance_2(mispelled_term)) probs = [] for term in corrected_terms: probs.append((term, spell.word_probability(term))) probs = sorted(probs, key=lambda x: x[1], reverse=True) new_corrected_terms = [term[0] for term in probs] new_query_terms.extend(new_corrected_terms[:3]) # Add top 3 corrections for t in new_corrected_terms[:3]: term_weights[t] = max(MISSPELLING_TERM_WEIGHT, term_weights[t]) # Preprocess terms and assign weights to the expanded query terms new_query = defaultdict(lambda: 0.0) for term in set(new_query_terms): for new_term in set(util.preprocess_content(term)): new_query[new_term] = max(term_weights[term], new_query[new_term]) new_query = [(term, weight) for term, weight in new_query.items()] return new_query