Альтернативний спосіб вилучення рядків з тексту (python-regex)

Я шукаю спосіб вилучення ліній з досить великої бази даних в Python. Мені потрібно зберегти лише ті, що містять одне з моїх ключових слів. Я думав, що я можу використовувати регулярні виразу, щоб вирішити проблему, і я зібрав код нижче. На жаль, це дає мені якісь помилки (можливо, також через те, що мої ключові слова, які написані окремими рядками у файлі listtosearch.txt, дійсно великі, майже 500).

import re
data = open('database.txt').read() 
fileout = open("fileout.txt","w+")

with open('listtosearch.txt', 'r') as f:
    keywords = [line.strip() for line in f]

pattern = re.compile('|'.join(keywords))

for line in data:
    if pattern.search(line):
        fileout.write(line)

Я також спробував використати подвійний цикл (як у списку ключових слів, так і в рядках бази даних), але це займе занадто багато часу для запуску.

Помилка, яку я отримую, це:

Traceback (most recent call last):
  File "/usr/lib/python2.7/re.py", line 190, in compile 
    return _compile(pattern, flags)   
  File "/usr/lib/python2.7/re.py", line 240, in _compile 
    p = sre_compile.compile(pattern, flags) 
  File "/usr/lib/python2.7/sre_compile.py", line 511, in compile 
    "sorry, but this version only supports 100 named groups" 
AssertionError: sorry, but this version only supports 100 named groups

Будь-яка пропозиція? Дякую

0
@ user2447387 це неможливо. Мій код не використовує модуль re , і у мене немає лінії порушення.
додано Автор brice, джерело
@ user2447387 це неможливо. Мій код не використовує модуль re , і у мене немає лінії порушення.
додано Автор brice, джерело
ну там ви йдете, це говорить вам, що ви не можете мати більше 100 під-виразів у вашому шаблоні регулярних виразів. не ваша провина. відповідь Брайс спрацює.
додано Автор rectummelancolique, джерело
Які помилки?
додано Автор rectummelancolique, джерело
Я знаю, вибачте, моя погана! Дозвольте мені виконати його належним чином
додано Автор user2447387, джерело
Я знаю, вибачте, моя погана! Дозвольте мені виконати його належним чином
додано Автор user2447387, джерело
Насправді це дає мені точно такі ж помилки, навіть коли я запускаю код Brice :(
додано Автор user2447387, джерело
Насправді це дає мені точно такі ж помилки, навіть коли я запускаю код Brice :(
додано Автор user2447387, джерело
Це дає мені такі помилки: pattern = re.compile ('|' .join (ключові слова)) Файл "/usr/lib/python2.7/re.py", рядок 190, у компіляції повернути _compile (шаблон, прапорці) Файл "/usr/lib/python2.7/re.py", рядок 240, у _compile p = sre_compile.compile (шаблон, прапори) Файл "/usr/lib/python2.7/sre_compile.py", рядок 511, у compile "sorry, але ця версія підтримує лише 100 іменних груп" AssertionError: sorry, але ця версія підтримує лише 100 іменних груп
додано Автор user2447387, джерело

7 Відповіді

Ви можете переглянути алгоритм відповідності рядків Aho – Corasick . Діючу реалізацію в Python можна знайти тут .

Простий приклад використання цього модуля:

from pyahocorasick import Trie

words = ['foo', 'bar']

t = Trie()
for w in words:
    t.add_word(w, w)
t.make_automaton()

print [a for a in t.iter('my foo is a bar')]

>> [(5, ['foo']), (14, ['bar'])]

Інтеграція у ваш код має бути простою.

2
додано
Я буду дивитися, спасибі, однак здається досить важким з огляду на мої обмежені поняття python і кодування в цілому :(
додано Автор user2447387, джерело

По-перше, я впевнений, що ви маєте на увазі data = open ('database.txt'). Readlines() , а не read() . Інакше data буде радком, а не списком рядків, і ваш для рядка в даних не матиме ніякого сенсу.

На даний момент, ви дійсно шукаєте рішення індексування за ключовим словом, і наївний пошук перестане бути ефективним, щоб дати вам вчасно результат.

Насправді немає іншого підходу, який би був набагато ефективнішим або менш складним. Ви повинні будете подрібнити зуби і прийняти вартість перегляду всієї бази даних.

Також, ваша база даних не може бути такою великою, якщо вона повністю вписується в пам'ять

Тим не менш, існують інші способи, які ви могли б зробити це, ймовірно, буде більш ефективним:

  1. Put your keywords in a set, then tokenise the input data into word and look all of them up in the set:

    data = open('database.txt').readlines() 
    fileout = open("fileout.txt","w+")
    
    with open('listtosearch.txt', 'r') as f:
      keywords = [line.strip() for line in f]
    
    keywords = set(keywords)
    
    for line in data:
        # You might have to be smarter about splitting the line to 
        # take things like punctuation into consideration.
        for word in line.split():
          if word in keywords:
            fileout.write(line)
            break
    

    Here's an example of word splitting that takes into account punctuation.

1
додано
Я не знаю, чому (на жаль, я новачок у python), але таким чином не витягується лінія. Мої ключові слова в цій формі: "назви імен" (рік) і повинні бути повністю узгоджені для вилучення рядка.
додано Автор user2447387, джерело

По-перше, я впевнений, що ви маєте на увазі data = open ('database.txt'). Readlines() , а не read() . Інакше data буде радком, а не списком рядків, і ваш для рядка в даних не матиме ніякого сенсу.

На даний момент, ви дійсно шукаєте рішення індексування за ключовим словом, і наївний пошук перестане бути ефективним, щоб дати вам вчасно результат.

Насправді немає іншого підходу, який би був набагато ефективнішим або менш складним. Ви повинні будете подрібнити зуби і прийняти вартість перегляду всієї бази даних.

Також, ваша база даних не може бути такою великою, якщо вона повністю вписується в пам'ять

Тим не менш, існують інші способи, які ви могли б зробити це, ймовірно, буде більш ефективним:

  1. Put your keywords in a set, then tokenise the input data into word and look all of them up in the set:

    data = open('database.txt').readlines() 
    fileout = open("fileout.txt","w+")
    
    with open('listtosearch.txt', 'r') as f:
      keywords = [line.strip() for line in f]
    
    keywords = set(keywords)
    
    for line in data:
        # You might have to be smarter about splitting the line to 
        # take things like punctuation into consideration.
        for word in line.split():
          if word in keywords:
            fileout.write(line)
            break
    

    Here's an example of word splitting that takes into account punctuation.

1
додано
Я не знаю, чому (на жаль, я новачок у python), але таким чином не витягується лінія. Мої ключові слова в цій формі: "назви імен" (рік) і повинні бути повністю узгоджені для вилучення рядка.
додано Автор user2447387, джерело

Можливо, це не є ефективним рішенням, але спробуйте скористатися властивостями набору та перетину.

from_db = tuple([line.rstrip("\n") for line in open('database.txt') if line.rstrip('\n')])
keywords = set([line.rstrip("\n") for line in open('listtosearch.txt') if line.rstrip('\n')])
with open("output_file.txt", "w") as fp:
    for line in from_db:
        line_set = set(line.split(" "))
        if line_set.intersection(keywords):
            fp.write(line + "\n")

Перехрестя перевірятиме наявність звичайних рядків. Оскільки порівнюються значення хешу, я вважаю, що пошук буде швидшим, а не буде виконуватися весь список знову і знову.

1
додано

Можливо, це не є ефективним рішенням, але спробуйте скористатися властивостями набору та перетину.

from_db = tuple([line.rstrip("\n") for line in open('database.txt') if line.rstrip('\n')])
keywords = set([line.rstrip("\n") for line in open('listtosearch.txt') if line.rstrip('\n')])
with open("output_file.txt", "w") as fp:
    for line in from_db:
        line_set = set(line.split(" "))
        if line_set.intersection(keywords):
            fp.write(line + "\n")

Перехрестя перевірятиме наявність звичайних рядків. Оскільки порівнюються значення хешу, я вважаю, що пошук буде швидшим, а не буде виконуватися весь список знову і знову.

1
додано

Ось мій код:

import re
data = open('database.txt', 'r')
fileout = open("fileout.txt","w+")

with open('listtosearch.txt', 'r') as f:
    keywords = [line.strip() for line in f]

# one big pattern can take time to match, so you have a list of them
patterns = [re.compile(keyword) for keyword in keywords]

for line in data:

    for pattern in patterns:
        if not pattern.search(line):
            break
    else:
        fileout.write(line)

Я перевірив його з такими файлами:

database.txt

"Name jhon" (1995)
"Name foo" (2000)
"Name fake" (3000)
"Name george" (2000)
"Name george" (2500)

listtosearch.txt

"Name (george)"
\(2000\)

І це те, що я отримую в fileout.txt

"Name george" (2000)

Так що це має працювати і на вашій машині.

1
додано
Я додав ще один ще на внутрішній цикл, щоб уникнути непотрібних перевірок регулярного виразу
додано Автор Lorenzo Persichetti, джерело
Потім слід перевірити свої моделі. Схоже, що жодна з ліній у database.txt не відповідає їх усіх.
додано Автор Lorenzo Persichetti, джерело
Тоді ви можете зробити цикл на рядку тільки з входом (як ви вже зробили, щоб прочитати ключові слова, я не помітив). Я змінив фрагмент, щоб також гарантувати, що всі регулярні вирази співпадають.
додано Автор Lorenzo Persichetti, джерело
Яку версію Python ви використовуєте?
додано Автор Lorenzo Persichetti, джерело
Я зробив ще кілька редагувань і тестів, перевірив їх.
додано Автор Lorenzo Persichetti, джерело
Я очистив код ще більше, використовуючи синтаксис for: else:
додано Автор Lorenzo Persichetti, джерело
Мій поганий як завжди, вибачте! Я забув уникнути дужки у списку ключових слів. Це має бути питання ... Дякую за терпіння! :)
додано Автор user2447387, джерело
Насправді є деякі збіги .. Я використовую подвыборку мого набору даних, щоб перевірити речі, і працює простий подвійний цикл, здається, працює нормально (за винятком того, що це займає багато часу)
додано Автор user2447387, джерело
:( Результати вихідного файлу знову порожні ... я дійсно не можу зрозуміти, чому
додано Автор user2447387, джерело
Я використовую python 2.7
додано Автор user2447387, джерело
Ключові слова знаходяться в цій формі: "Назва імені" (рік) і повинні бути повністю узгоджені (ім'я в "" і рік у дужках)
додано Автор user2447387, джерело
Я не знаю, чому (на жаль, я новачок у python), але таким чином не витягується лінія
додано Автор user2447387, джерело

Ось мій код:

import re
data = open('database.txt', 'r')
fileout = open("fileout.txt","w+")

with open('listtosearch.txt', 'r') as f:
    keywords = [line.strip() for line in f]

# one big pattern can take time to match, so you have a list of them
patterns = [re.compile(keyword) for keyword in keywords]

for line in data:

    for pattern in patterns:
        if not pattern.search(line):
            break
    else:
        fileout.write(line)

Я перевірив його з такими файлами:

database.txt

"Name jhon" (1995)
"Name foo" (2000)
"Name fake" (3000)
"Name george" (2000)
"Name george" (2500)

listtosearch.txt

"Name (george)"
\(2000\)

І це те, що я отримую в fileout.txt

"Name george" (2000)

Так що це має працювати і на вашій машині.

1
додано
Тоді ви можете зробити цикл на рядку тільки з входом (як ви вже зробили, щоб прочитати ключові слова, я не помітив). Я змінив фрагмент, щоб також гарантувати, що всі регулярні вирази співпадають.
додано Автор Lorenzo Persichetti, джерело
Яку версію Python ви використовуєте?
додано Автор Lorenzo Persichetti, джерело
Потім слід перевірити свої моделі. Схоже, що жодна з ліній у database.txt не відповідає їх усіх.
додано Автор Lorenzo Persichetti, джерело
Я зробив ще кілька редагувань і тестів, перевірив їх.
додано Автор Lorenzo Persichetti, джерело
Я додав ще один ще на внутрішній цикл, щоб уникнути непотрібних перевірок регулярного виразу
додано Автор Lorenzo Persichetti, джерело
Я очистив код ще більше, використовуючи синтаксис for: else:
додано Автор Lorenzo Persichetti, джерело
Насправді є деякі збіги .. Я використовую подвыборку мого набору даних, щоб перевірити речі, і працює простий подвійний цикл, здається, працює нормально (за винятком того, що це займає багато часу)
додано Автор user2447387, джерело
Я використовую python 2.7
додано Автор user2447387, джерело
Мій поганий як завжди, вибачте! Я забув уникнути дужки у списку ключових слів. Це має бути питання ... Дякую за терпіння! :)
додано Автор user2447387, джерело
:( Результати вихідного файлу знову порожні ... я дійсно не можу зрозуміти, чому
додано Автор user2447387, джерело
Ключові слова знаходяться в цій формі: "Назва імені" (рік) і повинні бути повністю узгоджені (ім'я в "" і рік у дужках)
додано Автор user2447387, джерело
Я не знаю, чому (на жаль, я новачок у python), але таким чином не витягується лінія
додано Автор user2447387, джерело
ІТ КПІ - Python
ІТ КПІ - Python
625 учасників

Канал обговорень про всякі штуки зі світу пайтону. Прохання: 0. мати повагу одне до одного; 1. не матюкатися в сторону людей; 2. не захламляти тред повідомленнями по одному слову;