2010-10-18 8 views
6

J'ai un fichier texte et je veux afficher tous les mots qui contiennent à la fois les caractères z et x.Comment "afficher" tous les mots qui contiennent ces caractères?

Comment puis-je faire cela?

+2

Où est le problème exact? Qu'avez-vous essayé jusqu'à présent? –

+0

Je ne sais pas comment analyser le fichier texte :) – xRobot

+0

Les expressions régulières sont très importantes en matière d'analyse de texte. Regardez la solution d'Ishpeck. – Squirrelsama

Répondre

11

Si vous ne voulez pas avoir 2 problèmes:

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

Dieu merci, vous avez fourni une réponse qui * n'utilise pas * les expressions régulières. – gotgenes

+0

+1: J'aime beaucoup ça. Le seul problème que je peux voir est que vous obtiendrez une ponctuation autour de vos mots, pas seulement les mots eux-mêmes. –

+0

Certes, j'utilise la définition de "mots" de python, qui pourrait être déraisonnable ici. – geoffspear

0

Cela ressemble à un travail pour Regular Expressions. Lisez ça et essayez-le. Si vous rencontrez des problèmes, mettez à jour votre question et nous pouvons vous aider avec les détails.

8

En supposant que vous avez le fichier entier comme une grande chaîne en mémoire, et que la définition d'un mot est « une séquence contiguë de lettres », alors vous pourriez faire quelque chose comme ceci:

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

J'aime cette réponse. C'est la solution la plus propre. Si la performance devient un problème, chronométrez-la contre ma solution et choisissez le gagnant. –

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

Je peux confirmer cela fonctionne et est mieux que ma réponse. Je vais supprimer le mien en faveur de celui-ci. – 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

Je ne connais pas les performances de ce générateur, mais pour moi t son est le chemin:

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

Je veux juste montrer comment musclées certaines de ces expressions régulières peuvent être, par rapport à la string methods-based solution provided by Wooble simple.

Faisons quelques minutages, n'est-ce pas?

#!/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" 

L'exécution de ce script sur un plaintext copy of Moby Dick obtenu à partir Project Gutenberg, sur Python 2.6, je reçois les horaires suivants:

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 (après avoir utilisé 2to3 pour fixer les instructions d'impression), je reçois les horaires suivants:

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 

On peut voir que les fonctions à base d'une expression régulière ont tendance à prendre deux fois plus de temps pour courir comme strin g la fonction basée sur les méthodes dans Python 2.6, et plus de 3 fois plus longtemps dans Python 3. La différence de temps est triviale pour l'analyse ponctuelle (personne ne manquera ces millisecondes), mais pour les cas où la fonction doit être appelée plusieurs fois, l'approche basée sur les méthodes de chaîne est à la fois plus simple et plus rapide.

+0

Je préfère aussi les méthodes de chaîne. Mais, voici un nitpick.J'ai changé la définition de zx_re_find (texte) et c'est 4x plus rapide que la méthode de chaîne pure: def zx_re_find (texte): pat = re.compile ('(\ b \ w * z \ w * \ b)') pour mot dans pat.findall (texte): si 'x' dans le mot: mot d'impression –

+0

@Steven J'ai mis à jour ma réponse à inclure inclure à la fois votre solution suggérée dans le commentaire, et la solution que vous avez fourni comme une réponse, et a fait n'obtient pas de performance 4X par une expression régulière par rapport à la méthode string. Pour moi, les solutions RE traînent toujours derrière. Quel texte avez-vous utilisé pour tester votre performance? – gotgenes

+0

@gotgenes J'ai utilisé la même copie en clair de Moby Dick. J'ai utilisé python 2.7 sur Windows XP (hmm .. oublié la puce dans mon ordinateur portable de travail). Je me souviens des 3 premiers chiffres des timings 0.311 pour la chaîne et 0.088 pour la regex (pas vraiment 4x, mais proche). Je maintiens que si les exigences étaient plus compliquées, la regex gagnerait en simplicité et en performance. –

Questions connexes