Bir metinde bir sayıdan önce ve sonra isim ifadesini bulun
Bir metin verildiğinde, bir check_words listesine (bir tür engellenecek kelimeler) ait bir durdurma kelimesine kadar tüm sayıların önceki kelimeleri bulmalıyım.
Kodum:
check_words = ['the', 'a', 'with','to']
mystring = 'the code to find the beautiful words 78 that i have to nicely check 45 with the snippet'
list_of_words = mystring.split()
Söz konusu metinde daha önce kontrol ederdim '78'
ve '45'
check_words'teki kelimelerin herhangi birini bulduğum noktaya kadar geri giderim (ancak 8 kelimeden fazla değil).
Bunu yapmanın kodu şunlar olabilir:
preceding_chunks = []
for i,word in enumerate(list_of_words):
if any(char.isdigit() for char in word):
# 8 precedent words (taking into account that I can not slice with 8 back at the beginning)
preceding_words = list_of_words[max(0,i-8):i]
preceding_words[::-1]
# I check from the end of the list towards the start
for j,sub_word in enumerate(preceding_words[::-1]):
if sub_word in check_words:
# printing out j for checking
myposition = j
print(j)
real_preceding_chunk = preceding_words[len(preceding_words)-j:]
print(real_preceding_chunk)
preceding_chunks.append(real_preceding_chunk)
break
Bu kod çalışıyor. temelde her kelimeyi kontrol ediyorum ama (belki yanılıyorum) birkaç gömlek ile ve dolayısıyla döngüler olmadan elde edilebileceği izlenimine sahibim. Herhangi bir fikir?
NOT: Bu soru, kodun okunabilirliğini iyileştirmek, kodu daha hızlı hale getirmek için döngülerden kurtulmaya çalışmak ve Python Zen'in bir parçası olan kodu daha güzel yapmaya çalışmakla ilgilidir.
NOT 2: Yaptığım bazı önceki kontroller:
- Finding the position of an item in another list from a number in a different list
- Finding the index of an item in a list
- Find in list
Yanıtlar
I came up with this:
import itertools
import re
chunks = (grouped_chunk.split() for grouped_chunk in re.split("\\s+\\d+\\s+", mystring))
preceding_chunks = []
for reversed_chunk in map(reversed, chunks):
preceding_chunk = list(itertools.takewhile(lambda word: word not in check_words, reversed_chunk))[::-1]
preceding_chunks.append(preceding_chunk)
We apply itertools.takewhile
to the reversed_chunk
which gives us the preceding chunk in reversed order. We then obtain the correctly ordered preceding_chunk
by reversing at the end with [::-1]
.
The regex splits mystring
based on a number (the escaped \d+
). The surrounding escaped \s+
s represent any padding around the number. This causes this code to have different behavior than yours if digits and letters are mixed in the same words (for example, a1
).
For your original code, I'd make a couple suggestions:
- Follow PEP 8. For example, add spacing after the comma in
i,word
. - Remove the redundant expression
preceding_words[::-1]
. While this does evaluate to the reversedpreceding_words
, because it is not in-place, the evaluation has no side-effects. Plus, you already perform this reversal inenumerate(preceding_words[::-1])
.