2010-10-18 19 views
6

Tengo un archivo de texto y quiero mostrar todas las palabras que contienen tanto z como x caracteres.¿Cómo mostrar todas las palabras que contienen estos caracteres?

¿Cómo puedo hacer eso?

+2

¿Dónde está el problema exacto? ¿Qué has intentado hasta ahora? –

+0

No sé cómo analizar el archivo de texto :) – xRobot

+0

Las expresiones regulares son el rey cuando se trata de análisis de texto. Mira la solución de Ishpeck. – Squirrelsama

Respuesta

11

Si no quiere tener problemas: 2

for word in file('myfile.txt').read().split(): 
    if 'x' in word and 'z' in word: 
     print word 
+1

Gracias a Dios que proporcionó una respuesta que * no * usa expresiones regulares. – gotgenes

+0

+1: Me gusta mucho esto. El único problema que puedo ver es que obtendrás cualquier puntuación que rodee tus palabras, no solo las palabras mismas. –

+0

Es cierto que estoy usando la definición de "palabras" de python, que podría ser irracional aquí. – geoffspear

0

Suena como un trabajo para Regular Expressions. Lee eso y pruébalo. Si tiene problemas, actualice su pregunta y podemos ayudarlo con los detalles.

8

Asumiendo que tiene el archivo completo como una gran cadena en la memoria, y que la definición de una palabra es "una secuencia contigua de letras", entonces se podría hacer algo como esto:

import re 
for word in re.findall(r"\w+", mystring): 
    if 'x' in word and 'z' in word: 
     print word 
+0

Me gusta esta respuesta. Es la solución más limpia. Si el rendimiento se convierte en un problema, compárelo con mi solución y elija al ganador. –

3
>>> import re 
>>> pattern = re.compile('\b(\w*z\w*x\w*|\w*x\w*z\w*)\b') 
>>> document = '''Here is some data that needs 
... to be searched for words that contain both z 
... and x. Blah xz zx blah jal akle asdke asdxskz 
... zlkxlk blah bleh foo bar''' 
>>> print pattern.findall(document) 
['xz', 'zx', 'asdxskz', 'zlkxlk'] 
+0

Puedo confirmar que esto funciona y es mejor que mi respuesta. Eliminaré el mío a favor de este. – Ishpeck

0
>>> import re 
>>> print re.findall('(\w*x\w*z\w*|\w*z\w*x\w*)', 'axbzc azb axb abc axzb') 
['axbzc', 'axzb'] 
1

que no conozco el funcionamiento de este generador, pero para mí t suyo es el camino:

from __future__ import print_function 
import string 

bookfile = '11.txt' # Alice in Wonderland 
hunted = 'az' # in your case xz but there is none of those in this book 

with open(bookfile) as thebook: 
    # read text of book and split from white space 
    print('\n'.join(set(word.lower().strip(string.punctuation) 
        for word in thebook.read().split() 
        if all(c in word.lower() for c in hunted)))) 
""" Output: 
zealand 
crazy 
grazed 
lizard's 
organized 
lazy 
zigzag 
lizard 
lazily 
gazing 
"" 

"

3

sólo quiero señalar cómo de mano dura algunas de estas expresiones regulares puede ser, en comparación con la sencilla string methods-based solution provided by Wooble.

Hagamos algunos tiempos, ¿de acuerdo?

#!/usr/bin/env python 
# -*- coding: UTF-8 -*- 

import timeit 
import re 
import sys 

WORD_RE_COMPILED = re.compile(r'\w+') 
Z_RE_COMPILED = re.compile(r'(\b\w*z\w*\b)') 
XZ_RE_COMPILED = re.compile(r'\b(\w*z\w*x\w*|\w*x\w*z\w*)\b') 

########################## 
# Tim Pietzcker's solution 
# https://stackoverflow.com/questions/3962846/how-to-display-all-words-that-contain-these-characters/3962876#3962876 
# 
def xz_re_word_find(text): 
    for word in re.findall(r'\w+', text): 
     if 'x' in word and 'z' in word: 
      print word 


# Tim's solution, compiled 
def xz_re_word_compiled_find(text): 
    pattern = re.compile(r'\w+') 
    for word in pattern.findall(text): 
     if 'x' in word and 'z' in word: 
      print word 


# Tim's solution, with the RE pre-compiled so compilation doesn't get 
# included in the search time 
def xz_re_word_precompiled_find(text): 
    for word in WORD_RE_COMPILED.findall(text): 
     if 'x' in word and 'z' in word: 
      print word 


################################ 
# Steven Rumbalski's solution #1 
# (provided in the comment) 
# https://stackoverflow.com/questions/3962846/how-to-display-all-words-that-contain-these-characters/3963285#3963285 
def xz_re_z_find(text): 
    for word in re.findall(r'(\b\w*z\w*\b)', text): 
     if 'x' in word: 
      print word 


# Steven's solution #1 compiled 
def xz_re_z_compiled_find(text): 
    pattern = re.compile(r'(\b\w*z\w*\b)') 
    for word in pattern.findall(text): 
     if 'x' in word: 
      print word 


# Steven's solution #1 with the RE pre-compiled 
def xz_re_z_precompiled_find(text): 
    for word in Z_RE_COMPILED.findall(text): 
     if 'x' in word: 
      print word 


################################ 
# Steven Rumbalski's solution #2 
# https://stackoverflow.com/questions/3962846/how-to-display-all-words-that-contain-these-characters/3962934#3962934 
def xz_re_xz_find(text): 
    for word in re.findall(r'\b(\w*z\w*x\w*|\w*x\w*z\w*)\b', text): 
     print word 


# Steven's solution #2 compiled 
def xz_re_xz_compiled_find(text): 
    pattern = re.compile(r'\b(\w*z\w*x\w*|\w*x\w*z\w*)\b') 
    for word in pattern.findall(text): 
     print word 


# Steven's solution #2 pre-compiled 
def xz_re_xz_precompiled_find(text): 
    for word in XZ_RE_COMPILED.findall(text): 
     print word 


################################# 
# Wooble's simple string solution 
def xz_str_find(text): 
    for word in text.split(): 
     if 'x' in word and 'z' in word: 
      print word 


functions = [ 
     'xz_re_word_find', 
     'xz_re_word_compiled_find', 
     'xz_re_word_precompiled_find', 
     'xz_re_z_find', 
     'xz_re_z_compiled_find', 
     'xz_re_z_precompiled_find', 
     'xz_re_xz_find', 
     'xz_re_xz_compiled_find', 
     'xz_re_xz_precompiled_find', 
     'xz_str_find' 
] 

import_stuff = functions + [ 
     'text', 
     'WORD_RE_COMPILED', 
     'Z_RE_COMPILED', 
     'XZ_RE_COMPILED' 
] 


if __name__ == '__main__': 

    text = open(sys.argv[1]).read() 
    timings = {} 
    setup = 'from __main__ import ' + ','.join(import_stuff) 
    for func in functions: 
     statement = func + '(text)' 
     timer = timeit.Timer(statement, setup) 
     min_time = min(timer.repeat(3, 10)) 
     timings[func] = min_time 


    for func in functions: 
     print func + ":", timings[func], "seconds" 

La ejecución de este script en un plaintext copy of Moby Dick obtenida de Project Gutenberg, en Python 2.6, consigo los siguientes tiempos:

xz_re_word_find: 1.21829485893 seconds 
xz_re_word_compiled_find: 1.42398715019 seconds 
xz_re_word_precompiled_find: 1.40110301971 seconds 
xz_re_z_find: 0.680151939392 seconds 
xz_re_z_compiled_find: 0.673038005829 seconds 
xz_re_z_precompiled_find: 0.673489093781 seconds 
xz_re_xz_find: 1.11700701714 seconds 
xz_re_xz_compiled_find: 1.12773990631 seconds 
xz_re_xz_precompiled_find: 1.13285303116 seconds 
xz_str_find: 0.590088844299 seconds 

En Python 3.1 (después de usar 2to3 para fijar las declaraciones de impresión), consigo los siguientes tiempos:

xz_re_word_find: 2.36110496521 seconds 
xz_re_word_compiled_find: 2.34727501869 seconds 
xz_re_word_precompiled_find: 2.32607793808 seconds 
xz_re_z_find: 1.32204890251 seconds 
xz_re_z_compiled_find: 1.34104800224 seconds 
xz_re_z_precompiled_find: 1.34424304962 seconds 
xz_re_xz_find: 2.33851099014 seconds 
xz_re_xz_compiled_find: 2.29653286934 seconds 
xz_re_xz_precompiled_find: 2.32416701317 seconds 
xz_str_find: 0.656699895859 seconds 

podemos ver que las funciones regulares basadas en expresiones tienden a tomar el doble de tiempo para ejecutarse como la strin g función basada en métodos en Python 2.6, y más de 3 veces más en Python 3. La diferencia de tiempo es trivial para el análisis único (nadie va a perder esos milisegundos), pero para los casos donde la función debe ser llamada muchas veces, el enfoque basado en métodos de cadena es tanto más simple como más rápido.

+0

Yo también prefiero los métodos de cadena. Pero, aquí hay un nitpick.Cambié la definición de zx_re_find (texto) y es 4 veces más rápido que el método de cadena pura: def zx_re_find (texto): pat = re.compile ('(\ b \ w * z \ w * \ b)') para palabra en pat.findall (texto): si 'x' en palabra: palabra de impresión –

+0

@Steven He actualizado mi respuesta para incluir incluir su solución sugerida en el comentario, y la solución que proporcionó como respuesta, y lo hice no obtiene el rendimiento 4X por ninguna expresión regular en comparación con el método de cadena. Para mí, las soluciones de RE todavía están detrás. ¿Qué texto usaste para probar tu desempeño? – gotgenes

+0

@gotgenes Utilicé la misma copia de texto claro de Moby Dick. Utilicé Python 2.7 en Windows XP (hmm ... olvidé el chip en mi portátil de trabajo). Recuerdo los primeros 3 dígitos de los tiempos 0.311 para la secuencia y 0.088 para la expresión regular (no realmente 4x, pero cerca). Sostengo que si los requisitos fueran más complicados, la expresión regular ganaría en simplicidad y rendimiento. –

Cuestiones relacionadas