Сбор похожих строк из локальных html-документов с использованием регулярных выражений Python - PullRequest
0 голосов
/ 06 июля 2018

У меня возникают проблемы при попытке получить набор похожих строк из набора текстовых (HTML) файлов с помощью регулярных выражений Python.Указанные файлы выглядят примерно так:

<!DOCTYPE html>
<html lang=fi>
<head>
<meta charset=UTF-8>
<title>Peruslaskutoimituksia</title>
<link rel=stylesheet type="text/css" href=
"https://math.tut.fi/mathcheck/mathcheck.css">
<script type="text/javascript" src=
"https://math.tut.fi/mathcheck/MathJax/MathJax.js?config=AM_HTMLorMML">
</script>
</head>

<body>
<h1>Peruslaskutoimituksia</h1>

<p>Kirjoita vastauksesi yhtäsuuruusmerkin jälkeen.

<form action="https://math.tut.fi/mathcheck/cgi-bin/mathcheck.out" method=post
target=_blank>
<table class=ifr>
<tr><td class=ifrl>

<p>1. Määritä luvun ` 9 ` käänteisluku.

<textarea name="hidden" style=display:none>
verbose_off
/* Tehtävä 1 */
arithmetic
f_nodes 4
1/( 9 )
</textarea>

<p><textarea rows=2 cols=30 autofocus name="exam">= </textarea>
<textarea name="hidden" style=display:none>end_of_answer</textarea>

<input type=submit formtarget=feedback1 value="submit, to the right">
</td><td class=ifrr>
<iframe name=feedback1 height=200></iframe></td></tr>
</table>
</form>

<form action="https://math.tut.fi/mathcheck/cgi-bin/mathcheck.out" method=post
target=_blank>
<table class=ifr>
<tr><td class=ifrl>

<p>2. Määritä luvun ` -4 ` vastaluku.

<textarea name="hidden" style=display:none>
verbose_off
/* Tehtävä 2 */
arithmetic
f_nodes 2
(-1)*( -4 )
</textarea>

<p><textarea rows=2 cols=30 name="exam">= </textarea>
<textarea name="hidden" style=display:none>end_of_answer</textarea>

<input type=submit formtarget=feedback2 value="submit, to the right">
</td><td class=ifrr>
<iframe name=feedback2 height=200></iframe></td></tr>
</table>
</form>

<form action="https://math.tut.fi/mathcheck/cgi-bin/mathcheck.out" method=post
target=_blank>
<table class=ifr>
<tr><td class=ifrl>

<p>3. Laske lausekkeen ` 7 /d^ 3 + 4 ` arvo, kun `d=3`. Anna vastaus
kokonaislukuna tai murtolukuna `a/b`, missä `a` ja `b` ovat kokonaislukuja.

<textarea name="hidden" style=display:none>
verbose_off
/* Tehtävä 3 */
arithmetic
f_nodes 3
7 /3^ 3 + 4
</textarea>

<p><textarea rows=2 cols=30 name="exam">= </textarea>
<textarea name="hidden" style=display:none>end_of_answer</textarea>

<input type=submit formtarget=feedback3 value="submit, to the right">
</td><td class=ifrr>
<iframe name=feedback3 height=200></iframe></td></tr>
</table>
</form>

<form action="https://math.tut.fi/mathcheck/cgi-bin/mathcheck.out" method=post
target=_blank>
<table class=ifr>
<tr><td class=ifrl>

<p>4. Laske lausekkeen `x^ 4 + x^ 3 ` arvo, kun `x = 3`.

<textarea name="hidden" style=display:none>
verbose_off
/* Tehtävä 4 */
arithmetic
f_nodes 1
3^ 4 + 3^ 3
</textarea>

<p><textarea rows=2 cols=30 name="exam">= </textarea>
<textarea name="hidden" style=display:none>end_of_answer</textarea>

<input type=submit formtarget=feedback4 value="submit, to the right">
</td><td class=ifrr>
<iframe name=feedback4 height=200></iframe></td></tr>
</table>
</form>

<form action="https://math.tut.fi/mathcheck/cgi-bin/mathcheck.out" method=post
target=_blank>
<table class=ifr>
<tr><td class=ifrl>

<p>5. Laske lausekkeen `( 8 )/( 5 ): ( 2 )/( 3 )` arvo murtolukuna `a/b`, missä
`a` ja `b` ovat kokonaislukuja.

<textarea name="hidden" style=display:none>
verbose_off
/* Tehtävä 5 */
arithmetic
f_nodes 3
(( 8 )/( 5 ))/(( 2 )/( 3 ))
</textarea>

<p><textarea rows=2 cols=30 name="exam">= </textarea>
<textarea name="hidden" style=display:none>end_of_answer</textarea>

<input type=submit formtarget=feedback5 value="submit, to the right">
</td><td class=ifrr>
<iframe name=feedback5 height=200></iframe></td></tr>
</table>
</form>

<hr>
<p class=unimp>This file was generated 2018-07-06 11:23:11 UTC.

</body>
</html>

Конкретные строки, которые я пытаюсь получить, - это строки, содержащиеся между тегами

<p>(some number). ...</textarea>,

, например

<p>1. Määritä luvun ` 9 ` käänteisluku.

<textarea name="hidden" style=display:none>
verbose_off
/* Tehtävä 1 */
arithmetic
f_nodes 4
1/( 9 )
</textarea>

Однако, вызов функции Python regex findall следующим образом

"""
Reading the assignments into memory from the produced HTML-files
"""
htmlDirEntries = sorted([filename for filename in os.listdir("./HTMLfiles") if filename.endswith(".html")])
# print(htmlDirEntries)

HTMLdict = {}
for filename in htmlDirEntries:
    print(f"Copying contents of {filename}...")
    with open(f"./HTMLfiles/{filename}", 'r') as f:
        filecontents = f.read()
        HTMLdict[filename] = filecontents
    print("Done.")

print()

print("Looking for and collecting assignments...")
print()

for filename in HTMLdict:
    print(filename)
    assignments = re.findall("<p>\d.+.*</textarea>", HTMLdict[filename], re.DOTALL)
    i = 1
    for assignment in assignments:
        print(f"Assignment {i}")
        i += 1
        print(assignment)

print("Done.")

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

'<p>1. Määritä luvun ` 7 ` käänteisluku.\n\n<textarea name="hidden" style=display:none>\nverbose_off\n/* Tehtävä 1 */\narithmetic\nf_nodes 4\n1/( 7 )\n</textarea>'

Вместо этого возвращается содержимое всего файла, начиная с первого <p>1. ....Я предполагаю, что мое использование re.findall неверно.

Интересно, почему метод findall не возвращает строку, заканчивающуюся на первый </textarea> после начального <p>?Что я здесь не так делаю?Моим первым предположением было бы посмотреть на регулярное выражение, данное findall, а именно: "<p>\d.+.*</textarea>" ...

РЕДАКТИРОВАТЬ:

Следующее выражение возвращает то, что я хочу, хотя это не такt работает во всех случаях:

assignments = re.findall(r"<p>\d+.+\n\n.+\n.+\n.+\n.+\n.+\n.+\n</textarea>", HTMLdict[filename])

С некоторыми файлами это возвращает пустой список, хотя я почти уверен, что они имеют одинаковый формат.

EDIT2

Оказывается, файлы не были в том же формате.В некоторых файлах есть дополнительные символы новой строки между начальным <p> -tag и <textarea...

1 Ответ

0 голосов
/ 06 июля 2018

Оказывается, это имеет отношение к жадности операторов * - и +. Добавление оператора? После того, как кто-либо из них исправил проблему:

assignments = re.findall("<p>\d+.[\s\S]+?</textarea>", HTMLdict[filename])

Здесь выражение [\s\S] относится ко всем возможным символам, включая символы новой строки. Я хотел, чтобы их было как можно больше, и в то же время получал как можно меньше тегов </textarea>, что требовало использования ограничивающего оператора ?.

...