2015-12-03 3 views
3

Учитывая список номеров элементов, я пытаюсь выполнить поиск в текстовом файле со списком последних номеров позиций и идентифицировать их в этом последнем списке. Затем я хочу добавить любые элементы, которые еще не были в недавнем списке.Невозможно найти строку в текстовом файле

Мой код ниже, он просто не находит ничего в текстовом файле. Почему он не работает?

def filter_recent_items(items): 
    recentitems = [] 
    with open('last 600 items.txt', 'r+') as f: 
     for item in items: 
      if item['ID'] in f: 
       print 'In! --', item['ID'] 
      else: 
       recentitems.append(item['ID']) 
       print 'Out ---', item['ID'] 
     for item in recentitems: 
      f.write("%s\n" % item) 


items = [ {'ID': 1}, {'ID': 'test2'} ]  
filter_recent_items(items) 

Например, мой текстовый файл:

test2 

test1 

1 

но приведенный выше код возвращает

Out --- 1 
Out --- test2 
+1

'if item ['ID'] в f' не делает то, что вы думаете. –

ответ

6

Проблема заключается в том, как вы проверяете на наличие указанного текста , В вашем коде f - это файловый объект, используемый для чтения и записи в/из файла. Он не содержит содержимого файла. Поэтому, когда вы проверяете,

str in f 

Это не проверка того, что вы думаете. Подробную информацию см. Ниже.)

Вместо этого вам необходимо прочитать строки и затем перебрать эти строки и проверить нужную строку. Ex.

with open('last 600 items.txt', 'r+') as f: 
    lines = f.readlines() 
    for l in lines: 
     # check within each line for the presence of the items 

В приведенном выше коде отрывке, f.readlines() использует объект файла для чтения содержимого файла и возвращает список строк, которые являются строками внутри файла.

EDITED (кредит Peter Wood)

Python Membership Details

В Python, когда вы используете синтаксис x in y, он проверяет на 2 вещи:

Case 1: сначала проверяет чтобы узнать, имеет ли метод y метод __contains__(b). Если это так, он возвращает результат y.__contains__(x).

Случай 2: Однако, если y делает не есть метод __contains__, но делает определить метод __iter__, Python использует вместо что метод перебора содержимого y и возвращает True, если в любой момент одно из значений, повторяющихся, равно x. В противном случае он возвращает False.

Если мы используем ваш код в качестве примера, в определенный момент он проверяет правду утверждения "test2" in f. Здесь f - объект типа file. (Python File Object Description). Файловые объекты относятся к случаю 2 (т.е. они не имеют __contains__, они сделать имеют __iter__.

Поэтому код будет проходить через каждую строку и посмотреть, будет ли ваши входные строки равного любых из строк в файле.И так как каждая строка заканчивается символом \n, ваши строки никогда не вернутся True.

Для разработки, в то время как "test2" in "test2\n" вернется True, тест, который на самом деле выполняется здесь: "test2" == "test2\n", который False.

Вы можете проверить, как это работает в вашем файле вручную. Для exmaple, если мы хотим, чтобы увидеть, если "test2" in f должен возвращать True:

with open(filename) as f: 
    x = iter(f) 
    while(True): 
     try: 
      line = x.next() 
     except: 
      break 
     print(line) 
     print(line == "test2") 

Вы заметите, что он печатает каждую строку (включая символ новой строки в конце), и что результат line == "test2" всегда False.

Если бы мы попытались: "test2\n" in f, результатом будет True.

End Edit

+0

'' test2 \ n 'in f' is 'True' –

+2

См. [Сведения о тестировании членства] (https://docs.python.org/2/reference/expressions.html#membership-test-details). 'in' будет использовать' iter', поскольку 'file' не определяет' __contains__', но определяет '__iter__'. Он будет повторяться до тех пор, пока он не будет исчерпан или пока не найдет совпадение. 'iter' вернет одну строку из файла, поэтому' 'test2 \ n'' будет соответствовать, тогда как' 'test2'' не будет. –

+2

Чтобы быть понятным, это должно быть точное совпадение. Из ссылки: * 'x in y' истинно, если какое-то значение' z' с 'x == z' создается при итерации над' y' * –

1

Распечатайте хранилище данных, е. Прежде всего, я ожидаю, что у вас есть встроенные символы новой строки, которые предотвращают совпадение элементов: «1» не соответствует «1 \ n». Во-вторых, обратите внимание, что ** с открытым "дает вам генератор, а не список или кортеж. Вы не можете сканировать список несколько раз. У вас нет данных от него до тех пор, пока вы его не перейдете через него.

Вам нужны коды, чтобы получить все элементы в память, такие как

content = f.read().split("\n") 
for item in items: 
    if item["ID" in content: 
+0

Кроме того, есть список словарей, действительно, что вы хотите для ввода? Я бы подумал, что сделает простой список, например ** [1, «item2»] **. – Prune

2

Как уже сказал, if "somestring" in f всегда будут терпеть неудачу. f является объектным файлом, который, когда вы итерации над ней, производит строки текста. Один или больше этих ЛИНИЙ может содержать ваш текст, поэтому вместо этого вы можете:

if any("targetstring" in line for line in f): 
    # success 

Это экономия памяти по сравнению с f.read() или f.readlines() подходами, которые одновременно передают весь файл в память, прежде чем что-либо делать.

@PeterWood указывает в комментариях, что некоторые из ваших целевых строк на самом деле не являются строками. Вы тоже должны это понять. all(isinstance(item["ID"], str) for item in items) должно быть True.

+0

Кроме того, первый 'item ['ID']' является 'int'. –

Смежные вопросы