Python, перебирать строки в файле; если строка равна строке в другом файле, вернуть исходную строку - PullRequest
1 голос
/ 28 августа 2011

Текстовый файл 1 имеет следующий формат:

'WORD': 1
'MULTIPLE WORDS': 1
'WORD': 2

и т.д.

Т.е. слово, разделенное двоеточием, за которым следует число.

Текстовый файл 2 имеет следующий формат:

'WORD'
'WORD'

и т.д..

Мне нужно извлечь отдельные слова (т. Е. Только WORD, а не MULTIPLE WORDS) из файла 1 и, если они соответствуют слову в файле 2, вернуть слово из файла 1 вместе с его значением.

У меня есть какой-то плохо работающий код:

def GetCounts(file1, file2):
    target_contents  = open(file1).readlines()  #file 1 as list--> 'WORD': n
    match_me_contents = open(file2).readlines()   #file 2 as list -> 'WORD'
    ls_stripped = [x.strip('\n') for x in match_me_contents]  #get rid of newlines

    match_me_as_regex= re.compile("|".join(ls_stripped))   

    for line in target_contents:
        first_column = line.split(':')[0]  #get the first item in line.split
        number = line.split(':')[1]   #get the number associated with the word
        if len(first_column.split()) == 1: #get single word, no multiple words 
            """ Does the word from target contents match the word
            from match_me contents?  If so, return the line from  
            target_contents"""
            if re.findall(match_me_as_regex, first_column):  
                print first_column, number

#OUTPUT: WORD, n
         WORD, n
         etc.

Из-за использования регулярных выражений выходные данные являются сомнительными. Код вернет, например, «asset, 2», поскольку re.findall () будет соответствовать «set» из match_me. Мне нужно сопоставить target_word со всем словом из match_me, чтобы заблокировать неверный вывод, полученный в результате частичного совпадения с регулярным выражением.

Ответы [ 8 ]

2 голосов
/ 28 августа 2011

Если file2 не слишком велико, добавьте их в набор:

file2=set(open("file2").read().split())
for line in open("file1"):
    if line.split(":")[0].strip("'") in file2:
        print line
1 голос
/ 28 августа 2011

Кажется, что это может быть просто особый случай grep. Если file2 - это, по сути, список шаблонов, а формат вывода такой же, как и для file1, то вы можете просто сделать это:

grep -wf file2 file1

-w указывает grep на совпадение только с целыми словами.

1 голос
/ 28 августа 2011

Полагаю, под "плохо функционирующим" ты подразумеваешь скорость?Потому что я проверил, и это, кажется, работает.

Вы могли бы сделать вещи более эффективными, сделав set слов в файле2:

word_set = set(ls_stripped)

И затем вместо findallвы бы увидели, если он в наборе:

in_set = just_word in word_set

Также чувствует себя чище, чем регулярное выражение.

0 голосов
/ 28 августа 2011

Давайте воспользуемся сходством формата файла с синтаксисом выражения Python:

from ast import literal_eval
with file("file1") as f:
  word_values = ast.literal_eval('{' + ','.join(line for line in f) + '}')
with file("file2") as f:
  expected_words = set(ast.literal_eval(line) for line in f)
word_values = {k: v for (k, v) in word_values if k in expected_words}
0 голосов
/ 28 августа 2011

Вот что я придумал:

def GetCounts(file1, file2):
    target_contents  = open(file1).readlines()  #file 1 as list--> 'WORD': n
    match_me_contents = set(open(file2).read().split('\n'))   #file 2 as list -> 'WORD'  
    for line in target_contents:
        word = line.split(': ')[0]  #get the first item in line.split
        if " " not in word:
            number = line.split(': ')[1]   #get the number associated with the word
            if word in match_me_contents:  
                print word, number

Изменения от вашей версии:

  • Перемещено для установки из регулярного выражения
  • Пошёл делить вместо readlines, чтобы избавиться от новых строк без дополнительной обработки
  • Изменено разделение слова на слова и проверка его длины на простую проверку, есть ли пробел в «слове» напрямую
    • Это может вызвать ошибку, если "пробел" не является фактическим пробелом. Однако это можно исправить с помощью регулярного выражения для "\ s" или эквивалентного ему, однако с ухудшением производительности.
  • Добавлен пробел в line.split (':'), чтобы номер пути не начинался с пробела
    • Это может вызвать ошибку, если перед числом нет пробела.
  • Перемещено number = line.split(': ')[1] после проверки, чтобы увидеть, содержит ли слово пробелы в целях эффективности, незначительной, хотя разница в скорости будет (почти наверняка большая часть времени будет потрачена на проверку, если работа была в цели)

Тем не менее, потенциальные ошибки могут возникать только в том случае, если фактические данные не соответствуют представленному вами формату.

0 голосов
/ 28 августа 2011

Мои два входных файла:

file1.txt * * 1004

'WORD': 1
'MULTIPLE WORDS': 1
'OTHER': 2

file2.txt

'WORD'
'NONEXISTENT'

Если file2.txt гарантированно не содержать несколько слов в строке, то нет необходимости явно фильтровать их из первого файла. Это будет сделано тестом членства:

# Build a set of what words we can return a count for.
with open('file2.txt', 'r') as f:
    allowed_words = set(word.strip() for word in f)

# See which of them exist in the first file.
with open('file1.txt', 'r') as f:
    for line in f:
        word, count = line.strip().split(':')

        # This assumes that strings with a space (multiple words) do not exist in
        # the second file.
        if word in allowed_words:
            print word, count

И выполнение этого дает:

$ python extract.py
'WORD' 1

Если file2.txt может содержать несколько слов, просто измените тест в цикле:

# Build a set of what words we can return a count for.
with open('file2.txt', 'r') as f:
    allowed_words = set(word.strip() for word in f)

# See which of them exist in the first file.
with open('file1.txt', 'r') as f:
    for line in f:
        word, count = line.strip().split(':')

        # This prevents multiple words from being selected.
        if word in allowed_words and not ' ' in word:
            print word, count

Заметьте, я не удосужился вычеркнуть цитаты из слов. Я не уверен, если это необходимо - это зависит от того, будет ли вход гарантированно иметь их или нет. Было бы тривиально добавить их.

Что-то еще, что вы должны учитывать, это чувствительность к регистру. Если строчные и прописные слова должны рассматриваться как одно и то же, перед преобразованием следует преобразовать все вводимые данные в прописные (или строчные, неважно, какие).

РЕДАКТИРОВАТЬ : Вероятно, было бы более эффективно удалить несколько слов из набора разрешенных слов, чем выполнять проверку в каждой строке file1:

# Build a set of what words we can return a count for.
with open('file2.txt', 'r') as f:
    allowed_words = set(word.strip() for word in f if not ' ' in f)

# See which of them exist in the first file.
with open('file1.txt', 'r') as f:
    for line in f:
        word, count = line.strip().split(':')

        # Check if the word is allowed.
        if word in allowed_words:
            print word, count
0 голосов
/ 28 августа 2011
import re, methodcaller

re_target = re.compile(r"^'([a-z]+)': +(\d+)", re.M|re.I)
match_me_contents = open(file2).read().splitlines()
match_me_contents = set(map(methodcaller('strip', "'"), match_me_contents))

res = []
for match in re_target.finditer(open(file1).read()):
    word, value = match.groups()
    if word in match_me_contents:
        res.append((word, value))
0 голосов
/ 28 августа 2011

Вот как я это сделаю.У меня нет под рукой интерпретатора Python, поэтому может быть несколько опечаток.

Одна из основных вещей, которые вы должны помнить при переходе на Python (особенно если это происходит из Perl), это то, что регулярные выражения обычноплохая идея: строковые методы мощные и очень быстрые.

def GetCounts(file1, file2):
    data = {}
    for line in open(file1):
        try:
            word, n = line.rsplit(':', 1)
        except ValueError: # not enough values
            #some kind of input error, go to next line
            continue
        n = int(n.strip())
        if word[0] == word[-1] == "'":
            word = word[1:-1]
        data[word] = n

    for line in open(file2):
        word = line.strip()
        if word[0] == word[-1] == "'":
            word = word[1:-1]
        if word in data:
            print word, data[word]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...