Можно ли искать txt-файл по словам из списка и вернуть строку выше? - PullRequest
0 голосов
/ 11 ноября 2018

У меня есть txt-файл с отправлениями, и я могу найти слова из списка в нем. Я хотел бы напечатать строку над 'found-line' в отдельный список. Я пробовал это с кодом ниже, но это только возвращает [].

Вот мой код:

fname_in = "test.txt"
lv_pos = []
search_list = ['word1', 'word2']

with open (fname_in, 'r') as f:
    file_l1 = [line.split('\n') for line in f.readlines()]
    counter = 0

    for word in search_list:
        if word in file_l1:
            l_pos.append(file_l1[counter - 1])

    counter += 1

print(l_pos)

Текстовый файл выглядит примерно так:

Bla bla bla
I want this line1.
I found this line with word1.
Bla bla bla
I want this line2.
I found this line with word2.

Результат, который я хочу это:

l_pos = ['I want this line1.','I want this line2.']

Ответы [ 3 ]

0 голосов
/ 11 ноября 2018

Прежде всего, вы получили некоторые опечатки в своем коде - в некоторых местах вы написали l_pos, а в других lv_pos.

Другая проблема в том, что я не думаю, что вы понимаете, что file_l1 - это список списков, поэтому if word in file_l1: не делает то, что вы думаете. Вам необходимо проверить каждый word по каждому из этих подсписков.

Вот некоторый рабочий код, основанный на вашем собственном:

fname_in = "simple_test.txt"
l_pos = []
search_list = ['word1', 'word2']

with open(fname_in) as f:
    lines = f.read().splitlines()

    for i, line in enumerate(lines):
        for word in search_list:
            if word in line:
                l_pos.append(lines[i - 1])

print(l_pos)  # -> ['I want this line1.', 'I want this line2.']

Обновление

Вот еще один способ сделать это, который не требует считывания всего файла в память сразу, поэтому не требует такого большого количества памяти:

from collections import deque

fname_in = "simple_test.txt"
l_pos = []
search_list = ['word1', 'word2']

with open(fname_in) as file:
    lines = (line.rstrip('\n') for line in file)  # Generator expression.

    try:  # Create and initialize a sliding window.
        sw = deque(next(lines), maxlen=2)
    except StopIteration:  # File with less than 1 line.
        pass

    for line in lines:
        sw.append(line)
        for word in search_list:
            if word in sw[1]:
                l_pos.append(sw[0])

print(l_pos)  # -> ['I want this line1.', 'I want this line2.']
0 голосов
/ 11 ноября 2018

Рассматривать файл как набор пар из строк и строк до :

[prev for prev,this in zip(lines, lines[1:]) 
                    if 'word1' in this or 'word2' in this]
#['I want this line1.', 'I want this line2.']

Этот подход может быть расширенным , чтобы охватить любое количество слов:

words = {'word1', 'word2'}
[prev for prev,this in zip(lines,lines[1:]) 
           if any(word in this for word in words)]
#['I want this line1.', 'I want this line2.']

Наконец , если вам нужны правильные слова, а не вхождения (как в "thisisnotword1"), вам следует правильно разметить строки, скажем, nltk.word_tokenize():

from nltk import word_tokenize
[prev for prev,this in zip(lines,lines[1:]) 
           if words & set(word_tokenize(this))]
#['I want this line1.', 'I want this line2.']
0 голосов
/ 11 ноября 2018

Во второй строке вашего примера вы написали lv_pos вместо l_pos. Внутри оператора with вы можете это исправить следующим образом:

fname_in = "test.txt"
l_pos = []
search_list = ['word1', 'word2']

file_l1 = f.readlines()

for line in range(len(file_l1)):
    for word in search_words:
        if word in file_l1[line].split(" "):
            l_pos.append(file_l1[line - 1])

print(l_pos)

Я не в восторге от этого решения, но думаю, что оно исправит ваш код с минимальными изменениями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...