2010-10-18 24 views
6

Mam plik tekstowy i chcę wyświetlić wszystkie słowa zawierające zarówno znaki Z, jak i X.Jak wyświetlić wszystkie słowa zawierające te znaki?

Jak mogę to zrobić?

+2

Gdzie jest dokładnie problem? Czego spróbowałeś do tej pory? –

+0

Nie wiem, jak przeanalizować plik tekstowy :) – xRobot

+0

Wyrażenia regularne są królem, jeśli chodzi o przetwarzanie tekstu. Spójrz na rozwiązanie Ishpecka. – Squirrelsama

Odpowiedz

11

Jeśli nie chcesz mieć 2 problemy:

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

Dzięki Bogu dostałeś odpowiedź, która * nie * używa wyrażeń regularnych. – gotgenes

+0

+1: Bardzo to lubię. Jedyny problem, jaki widzę, to to, że dostaniesz również interpunkcję otaczającą twoje słowa, a nie tylko same słowa. –

+0

To prawda, używam definicji Pythona "słów", co może być tutaj nieuzasadnione. – geoffspear

0

Brzmi jak zadanie dla Regular Expressions. Przeczytaj to i wypróbuj. Jeśli napotkasz problemy, zaktualizuj swoje pytanie, a my pomożemy ci w szczegółach.

8

Zakładając, że cały plik jako jeden duży ciąg w pamięci i że definicja słowa jest „ciągłą sekwencję liter”, a następnie można zrobić coś takiego:

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

Podoba mi się ta odpowiedź. To najczystsze rozwiązanie. Jeśli wydajność staje się problemem, pomniejsz go o moje rozwiązanie i wybierz zwycięzcę. –

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

Potwierdzam, że to działa i jest lepsze niż moja odpowiedź. Usuwam moje na korzyść tego. – 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

nie wiem skuteczność tego generatora, ale dla mnie t jego jest droga:

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

Chcę tylko podkreślić, jak brutalne niektóre z tych wyrażeń regularnych może być, w stosunku do prostego string methods-based solution provided by Wooble.

Zrobimy trochę czasu, dobrze?

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

Uruchomienie tego skryptu na plaintext copy of Moby Dick uzyskanych od Project Gutenberg, na Python 2.6, mam następujące czasy:

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 

w Pythonie 3.1 (po użyciu 2to3 naprawić sprawozdania z tuszem), otrzymuję następujące czasy:

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 

Widzimy, że funkcje oparte na regularnych wyrażeniach zwykle zajmują dwa razy więcej czasu niż strin g oparta na metodach w Pythonie 2.6 i ponad 3 razy dłuższa w Pythonie 3. Różnica czasu jest trywialna dla jednorazowego parsowania (nikt nie będzie tęsknił za tymi milisekundami), ale w przypadkach, w których funkcja musi być wywołana wiele razy, podejście oparte na metodach łańcuchowych jest prostsze i szybsze.

+0

Ja też wolę metody string. Ale tutaj jest dzioba.Zmieniłem definicję zx_re_find (text) i jest to 4x szybsze niż metoda czystego łańcucha: def zx_re_find (text): pat = re.compile ('(\ b \ w * z \ w * \ b)') dla słowo w pat.findall (text): jeśli "x" w słowie: wydrukuj słowo –

+0

@Steven Zaktualizowałem swoją odpowiedź, aby uwzględnić zarówno sugerowane rozwiązanie w komentarzu, jak i rozwiązanie podane przez Ciebie jako odpowiedź, i nie uzyskuje wydajności 4X według wyrażenia regularnego w porównaniu do metody łańcuchowej. Dla mnie rozwiązania RE wciąż pozostają w tyle. Jakiego tekstu użyłeś do przetestowania swojego występu? – gotgenes

+0

@gotgenes Użyłem tej samej kopii tekstu Moby Dicka. Użyłem Pythona 2.7 na Windows XP na (hmm .. zapomniałem chip w moim laptopie pracy). Pamiętam pierwsze 3 cyfry czasu 0.311 dla ciągu i 0.088 dla regex (nie naprawdę 4x, ale blisko). Uważam, że gdyby wymagania były bardziej skomplikowane, regex zyskałby na prostocie i wydajności. –

Powiązane problemy