2013-07-19 20 views
10

Czy są jakieś biblioteki, które mogą pobrać tekst (np. Dokument HTML) i listę ciągów znaków (np. Nazwy niektórych produktów), a następnie znaleźć wzór na liście łańcuchów i wygenerować wyrażenie regularne, które wyodrębniłoby wszystkie ciągi w tekście (dokument HTML), które pasują do znalezionego wzorca?Biblioteka Pythona do generowania wyrażeń regularnych

Na przykład, biorąc pod uwagę następujący kod 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> 

i poniższa lista ciągów:

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

Chciałbym funkcji, która będzie budować regex jak poniżej:

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

a następnie wyodrębnij wszystkie informacje z pliku html zgodnego z wyrażeniem regularnym. W tym przypadku wyjście byłoby:

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

Wyjaśnienie:

Chciałbym funkcja patrzeć na otaczający próbek, a nie na samych próbek. Tak więc, na przykład, jeśli html było:

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

i próbki ['Word', 'More words'] Chciałabym to aby wyodrębnić:

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

Dlaczego nie budować wyrażenie "Produkt [1-3]"? – mgilson

+5

Powiązane: http://stackoverflow.com/questions/616292/is-it-possible-for-a-computer-to-learn-a-regular-expression-by-user-provided-e –

+0

@mgilson Powinno spróbować generalizować jak najwięcej, a nie pasować więcej niż przykłady (lista ciągów znaków) ... –

Odpowiedz

-1

Zamiast generowania regex, jak o korzystaniu z bardziej ogólną regex ? Jeśli dane są ograniczone do wewnętrznej tekście elementu, który sam nie zawiera elementów, to wyrażenie regularne stosować re.findall przyniesie listę krotki gdzie każdy krotka (zmienna tekst)

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

Następnie można łatwo wyodrębnić tekst z każdej krotki.

+0

NB to wyrażenie używa specyficznej dla Pythona składni dla nazwanych grup, ale są one dostępne w większości innych smaków przy użyciu różnych składni. –

8

Twoje wymagania są w tym samym czasie bardzo szczegółowe i bardzo ogólne.

Nie sądzę, że kiedykolwiek znajdziesz bibliotekę dla swojego celu, chyba że sam napiszesz.

Z drugiej strony, jeśli spędzasz zbyt wiele czasu pisząc regex, można korzystać z niektórych narzędzi graficznych, aby pomóc im budować, jak: http://www.regular-expressions.info/regexmagic.html

Jednakże, jeśli trzeba wyodrębnić dane z dokumentów HTML tylko, powinieneś rozważyć użycie parsera html, powinno to znacznie ułatwić.

Polecam beautifulsoup do analizowania dokumentu HTML w Pythonie: https://pypi.python.org/pypi/beautifulsoup4/4.2.1

+0

Regexmagic nie jest dobre dla moich potrzeb. Zacząłem pracę z biblioteką i używam beautifulsoup4 do parsowania html. Opublikuję go tutaj, gdy mam stabilną wersję. –

0

Być może lepiej byłoby użyć parsera Pythona HTML, który obsługuje XPATHs (patrz this related question), poszukaj bitów zainteresowania w kodzie HTML , a następnie nagrać ich XPATH - lub przynajmniej te udostępnione przez więcej niż jeden z przykładów?

2

Miałem podobny problem. Pyparsing to świetne narzędzie do robienia dokładnie tego, co powiedziałeś.

http://pyparsing.wikispaces.com/

To pozwala na budowanie wyrażeń znacznie lista regex ale znacznie bardziej elastyczny. Witryna ma kilka dobrych przykładów.

Oto szybki skrypt dla tego problemu stwarzanego powyżej:

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

Tylko dla mojej ciekawości: co program powyżej drukuje? –

5

Jestem całkiem pewien, że odpowiedź na to pytanie w ogólnym przypadku (bez bycia pedantyczny) jest nr. Problem polega na tym, że dowolny tekst wraz z dowolnym zbiorem podciągów tego tekstu nie określa ściśle pojedynczego wyrażenia regularnego.

Jak wspomniano parę osób, funkcja może po prostu zwrócić .* dla każdego zestawu wejść. Lub może powrócić na ciągach ['desired', 'input', 'strings'], regex

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

Or mnóstwo innych trywialnie, ale całkowicie bezużyteczne poprawnych wyników.

Problem, przed którym stoisz, polega na tym, że aby zbudować wyrażenie regularne, musisz je rygorystycznie zdefiniować. Aby to zrobić, musisz opisać pożądane wyrażenie używając języka tak ekspresyjnego jak język regex, w którym pracujesz ... ciąg plus lista podłańcuchów nie jest wystarczająca (wystarczy spojrzeć na wszystkie opcje potrzebne narzędzie, takie jak RegexMagic do obliczania wyrażeń regularnych w ograniczonym środowisku!). W praktyce oznacza to, że potrzebujesz prawidłowego wyrażenia, które chcesz, aby go efektywnie obliczyć.


Oczywiście, zawsze można pójść drogą milion małp i próbę ewoluować odpowiednim regex jakoś, ale jesteś wciąż będziemy mieć problem wymagający ogromny wkład próbki tekstu + oczekiwano wyjście w celu uzyskania realnego wyrażenia. Poza tym upłynie wiele wieków, a od niedzieli na pewno będzie nadpobudliwość z nieprzydatnymi odpadami. Najlepiej byłoby napisać to samemu.

+0

Być może to było moje zło, ponieważ nie było jasne, ale nie chcę funkcji skonstruowania regexu, patrząc na próbki, ale patrząc na otoczenie próbek. Zatem ostateczne wyrażenie regularne będzie zawsze w następującej formie: 'before_regex' +' (. *?) '+' After_regex', gdzie '(. *?)' Będzie przechwytywać próbki. –

+1

@IonutHulub Żądanie dłuższego wyrażenia regularnego nie zmienia podstawowego problemu, ponieważ dane wejściowe, które chcesz podać, nie są wystarczająco ekspresyjne, aby opisać wyrażenie regularne. Mogę wymyślić dowolną liczbę wyrażeń regularnych w postaci 'before + (group) + after', z których wszystkie są" poprawne "i żadne z nich nie są rzeczywiście użyteczne. 'a * (sample) b *', 'b * (sample) a *', etc ... Wejścia, których chcesz użyć, są po prostu niewystarczające do danego zadania. –

+0

@HenryKeiter Nie dołączaj próbek do wyrażenia regularnego. Spójrz tylko na otoczenie. W podanym przykładzie, funkcja powinna zauważyć, że wszystkie 3 próbki mają '' przed nimi i '' po, więc powinno zbudować wyrażenie takie jak ' (. *?)'. Jest to możliwe ... Tworzę prototyp w ciągu ~ 2 godzin. Pracuję nad niektórymi innymi projektami, ale opublikuję bibliotekę tutaj, kiedy skończę. –

1

Spróbuj tego:

https://github.com/noprompt/frak

Jest napisany w Clojure i nie ma gwarancji, co wyprowadza jest najbardziej zwięzły wyraz, ale wydaje się mieć pewien potencjał

+0

Można również zmodyfikować algorytm eliminacji kandydatów, opracowany przez Toma Mitchella w celu przeprowadzenia regem learning: http://artint.info/html/ArtInt_193.html. Zacząłbyś od wyrażeń regularnych dopasowujących zdania słowo po słowie, a następnie uogólniaj je, usuwając słowa. – Simon

Powiązane problemy