2013-07-19 3 views
10

Есть ли там lib, который может взять текст (например, html-документ) и список строк (например, имя некоторых продуктов), а затем найти шаблон в списке строк и сгенерировать регулярное выражение, которое будет извлекать все строки в тексте (html document), которые соответствуют найденному шаблону?Библиотека Python для генерации регулярных выражений

К примеру, учитывая следующие HTML:

<table> 
    <tr> 
    <td>Product 1</td> 
    <td>Product 2</td> 
    <td>Product 3</td> 
    <td>Product 4</td> 
    <td>Product 5</td> 
    <td>Product 6</td> 
    <td>Product 7</td> 
    <td>Product 8</td> 
    </tr> 
</table> 

и следующий список строк:

['Product 1', 'Product 2', 'Product 3'] 

Я хотел бы функцию, которая будет строить регулярное выражение вроде следующего:

'<td>(.*?)</td>' 

а затем извлечь всю информацию из html, которые соответствуют регулярному выражению. В этом случае результат будет:

['Product 1', 'Product 2', 'Product 3', 'Product 4', 'Product 5', 'Product 6', 'Product 7', 'Product 8'] 

ПОЯСНЕНИЯ:

Я хотел бы функцию, чтобы смотреть на окружающих образцов, а не на самих образцов. Так, например, если HTML был:

<tr> 
    <td>Word</td> 
    <td>More words</td> 
    <td>101</td> 
    <td>-1-0-1-</td> 
</tr> 

и образцы ['Word', 'More words'] Я хотел бы, чтобы извлечь:

['Word', 'More words', '101', '-1-0-1-'] 
+14

Почему не так строить регулярное выражение ''Product [1-3]''? – mgilson

+5

Связанный: http://stackoverflow.com/questions/616292/is-it-possible-for-a-computer-to-learn-a-regular-expression-by-user-provided-e –

+0

@mgilson Он должен попробовать чтобы обобщать как можно больше, не сравнивая больше, чем примеры (список строк) ... –

ответ

-1

Вместо того, чтобы генерировать регулярное выражение, как об использовании более общего регулярное выражение ? Если данные ограничены к внутреннему тексту элемента, который сам по себе не содержит элементов, то это регулярное выражение используется с re.findall даст список кортежей, где каждый кортеж (тэг, текст):

r'<(?P<tag>[^>]*)>([^<>]+?)</(?P=tag)>' 

Вы могли бы извлечь из текста только текст из каждого кортежа.

+0

NB это регулярное выражение использует синтаксис, специфичный для python для названных групп, но они доступны в большинстве других вкусов, используя другой синтаксис. –

8

Ваше требование в то же время очень конкретное и очень общее.

Я не думаю, что вы когда-либо находили какую-либо библиотеку для своих целей, если не будете писать свои собственные.

С другой стороны, если вы проводите слишком много времени на написание регулярных выражений, вы можете использовать некоторые графические инструменты, чтобы помочь вам построить их, как: http://www.regular-expressions.info/regexmagic.html

Однако, если вам необходимо извлечь данные из HTML документов только вам следует подумать об использовании анализатора html, это должно сделать многое намного проще.

Я рекомендую beautifulsoup для разбора HTML документ в Python: https://pypi.python.org/pypi/beautifulsoup4/4.2.1

+0

Regexmagic не подходит для моих нужд. Я начал работу с библиотекой, и я использую beautifulsoup4 для анализа html. Я отправлю его здесь, когда у меня будет стабильная версия. –

0

Возможно, было бы лучше использовать анализатор Python HTML, который поддерживает XPaths (см this related question), обратите внимание на биты, представляющие интерес в HTML-коде , а затем записать их XPATH - или, по крайней мере, те, которые разделены более чем одним из примеров?

2

У меня была аналогичная проблема. Pyparsing - отличный инструмент, чтобы сделать то, что вы сказали.

http://pyparsing.wikispaces.com/

Это позволяет строить выражения гораздо список регулярных выражений, но гораздо более гибким. На сайте есть несколько хороших примеров.

Вот быстрый скрипт для задачи вы поставленный выше:

from pyparsing import * 
cell_contents = [] 
results = [] 
text_string="""<table> 
<tr> 
    <td>Product 1</td> 
    <td>Product 2</td> 
    <td>Product 3</td> 
    <td>Product 4</td> 
    <td>Product 5</td> 
    <td>Product 6</td> 
    <td>Product 7</td> 
    <td>Product 8</td> 
</tr> 
</table>""" 

text_string = text_string.splitlines() 
for line in text_string: 
    anchorStart,anchorEnd = makeHTMLTags("td") 
    table_cell = anchorStart + SkipTo(anchorEnd).setResultsName("contents") + anchorEnd 
    for tokens,start,end in table_cell.scanString(line): 
     cell_contents = ''.join(tokens.contents) 
     results.append(cell_contents) 

for i in results: 
    print i 
+0

Просто для моего любопытства: что программа выше печатает? –

5

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

Как упомянуто парой людей, функция может просто вернуть .* для каждого набора входов. Или он может вернуться, для ввода строк ['desired', 'input', 'strings'], регулярного выражения

'(desired)+|(input)+|(strings)+' 

Или много других тривиального правильных, но совершенно бесполезных результатов.

Проблема, с которой вы сталкиваетесь, заключается в том, что для создания регулярного выражения вам необходимо строго определить его. И для этого вам нужно описать желаемое выражение, используя язык как выразительный, как язык регулярных выражений, в котором вы работаете ... строка и список подстрок недостаточно (просто посмотрите на все параметры, такие как инструмент RegexMagic для вычисления регулярных выражений в ограниченной среде!). С практической точки зрения это означает, что вам нужно регулярное выражение, которое вы хотите, чтобы его эффективно вычислить.


Конечно, вы всегда можете пойти по пути миллион обезьян и попытку эволюционировать соответствующее регулярное выражение как-то, но вы все еще будете иметь проблемы требует огромного ввода образца текста + ожидается чтобы получить жизнеспособное выражение. Плюс это займет много времени, чтобы бежать и, вероятно, раздуваться шесть способов с воскресенья с бесполезным детритом. Скорее всего, вам лучше написать это самостоятельно.

+0

Возможно, это было плохо для того, чтобы я не был достаточно ясен, но я не хочу, чтобы функция создавала регулярное выражение, просматривая образцы, но смотря на окрестности образцов. Поэтому окончательное регулярное выражение всегда будет иметь следующий вид: 'before_regex' +' (. *?) '+' After_regex', где '(. *?)' Будет ловить образцы. –

+1

@IonutHulub Запрос более длинного регулярного выражения не изменяет основную проблему, которая заключается в том, что ввод, который вы надеетесь предоставить, просто недостаточно выразителен, чтобы описать регулярное выражение. Я могу придумать любое количество регулярных выражений формы 'before + (group) + after', все из которых являются« правильными », и ни одна из них на самом деле не является полезной. 'a * (sample) b *', 'b * (sample) a *' и т. д. Входы, которые вы хотите использовать, просто недостаточны для задачи. –

+0

@HenryKeiter Не включайте образцы в регулярное выражение. Посмотрите только на окрестности. В приведенном выше примере функция должна заметить, что все три образца имеют перед ними '' и '', поэтому он должен построить регулярное выражение, подобное' (. *?) '. Это выполнимо ... Я делаю прототип через ~ 2 часа. Я сейчас работаю над некоторыми другими проектами для работы, но я буду публиковать библиотеку здесь, когда закончу это. –

1

Попробуйте это:

https://github.com/noprompt/frak

Это написано в Clojure, и нет никаких гарантий того, что она выводит наиболее краткое выражение, но, кажется, есть некоторый потенциал

+0

Вы также можете изменить алгоритм устранения кандидатов, разработанный Томом Митчеллом для выполнения рег-обучения: http://artint.info/html/ArtInt_193.html. Вы начнете с регулярных выражений, которые соответствуют предложениям слово в слово, а затем обобщите их, удалив слова. – Simon

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