Analizar palabras únicas de un archivo de texto

Estoy trabajando en un proyecto para analizar palabras únicas de una gran cantidad de archivos de texto. Tengo el archivo manejado hacia abajo, pero estoy tratando de refinar el procedimiento de análisis. Cada archivo tiene un segmento de texto específico que termina con ciertas frases que estoy captando con una expresión regular en mi sistema en vivo.

El analizador debe recorrer cada línea y verificar cada palabra con 3 criterios:

  1. Más largo que dos personajes
  2. No en un diccionario predefinido. dict_file
  3. Aún no en la lista de palabras

El resultado debe ser una matriz 2D, cada fila es una lista de palabras únicas por archivo, que se escribe en un archivo CSV utilizando el .writerow(foo) después de procesar cada archivo.

Mi código de trabajo está abajo, pero es lento y confuso, ¿qué me estoy perdiendo?

Mi sistema de producción está ejecutando 2.5.1 con solo los módulos predeterminados (por lo que NLTK es un no-go), no se puede actualizar a 2.7+.

 def process(line): line_strip = line.strip() return line_strip.translate(punct, string.punctuation) # Directory walking and initialization here report_set = set() with open(fullpath, 'r') as report: for line in report: # Strip out the CR/LF and punctuation from the input line line_check = process(line) if line_check == "FOOTNOTES": break for word in line_check.split(): word_check = word.lower() if ((word_check not in report_set) and (word_check not in dict_file) and (len(word) > 2)): report_set.append(word_check) report_list = list(report_set) 

Edición: Actualicé mi código basado en las recomendaciones de steveha.

Un problema es que una prueba para una list es lenta. Probablemente debería mantener un set para realizar un seguimiento de las palabras que ha visto, ya que la prueba para un set es muy rápida.

Ejemplo:

 report_set = set() for line in report: for word in line.split(): if we_want_to_keep_word(word): report_set.add(word) 

Luego, cuando haya terminado: report_list = list (report_set)

En cualquier momento que necesite forzar un set en una list , puede hacerlo. Pero si solo necesitas hacer un bucle o hacer pruebas, puedes dejarlo como un set ; es legal hacer for x in report_set:

Otro problema que puede o no puede ser importante es que estás barriendo todas las líneas del archivo de una sola vez, usando el método .readlines() . Para archivos realmente grandes, es mejor usar el objeto abierto de manejo de archivos como un iterador, así:

 with open("filename", "r") as f: for line in f: ... # process each line here 

Un gran problema es que ni siquiera veo cómo puede funcionar este código:

 while 1: lines = report.readlines() if not lines: break 

Esto se repetirá para siempre. La primera statement arrastra todas las líneas de entrada con .readlines() , luego hacemos un bucle de nuevo, luego la siguiente llamada a .readlines() ya está agotada, por lo que la llamada a .readlines() devuelve una lista vacía, Bucle infinito. Pero esto ahora ha perdido todas las líneas que acabamos de leer, y el rest del código debe conformarse con una variable de lines vacías. ¿Cómo funciona esto incluso?

Por lo tanto, deshágase de todo ese bucle while 1 , y cambie el siguiente bucle a for line in report:

Además, no es necesario mantener una variable de count . Puede usar len(report_set) en cualquier momento para averiguar cuántas palabras hay en el set .

Además, con un set no es necesario comprobar si hay una palabra in el conjunto; simplemente puede llamar a report_set.add(word) y si ya está en el set , no se agregará nuevamente.

Además, no tiene que hacerlo a mi manera, pero me gusta hacer un generador que haga todo el procesamiento. Pele la línea, traduzca la línea, divida en espacios en blanco y ceda las palabras listas para usar. También forzaría las palabras a minúsculas, excepto que no sé si es importante que las FOOTNOTES se detecten solo en mayúsculas.

Entonces, pon todo lo anterior juntos y obtendrás:

 def words(file_object): for line in file_object: line = line.strip().translate(None, string.punctuation) for word in line.split(): yield word report_set = set() with open(fullpath, 'r') as report: for word in words(report): if word == "FOOTNOTES": break word = word.lower() if len(word) > 2 and word not in dict_file: report_set.add(word) print("Words in report_set: %d" % len(report_set)) 

Intente reemplazar report_list con un diccionario o conjunto. word_check no en report_list funciona lento si report_list es una lista