Найти числа в строке и уменьшить их

У меня есть HTML-страница, в которой перечислены длинные индексы тем и номеров страниц. Я хочу найти все номера страниц и их ссылки на теги привязки и уменьшить номера страниц на 1.

Вот пример строки в HTML:

<p class="index">breakeven volume (BEV), <a href="ch02.xhtml#page28">28</a></p>

Я пытаюсь найти число 28 в обоих местах и ​​уменьшить его на 1.

Пока мне удалось найти число и заменить его самим собой, но я не могу понять, как его уменьшить. Мой код до сих пор:

import fileinput
import re

for line in fileinput.input():
    line = re.sub(r'\>([0-9]+)\<', r'>\1<', line.rstrip())
    print(line)

person John Gayle    schedule 07.04.2015    source источник


Ответы (2)


Вы можете использовать функцию замены при замене:

import re
s = '<p class="index">breakeven volume (BEV), <a href="ch02.xhtml#page28">28</a></p>'
re.sub(r'page(\d+)">\1', lambda m: 'page{0}">{0}'.format(int(m.group(1)) - 1), s)

Результат:

<p class="index">breakeven volume (BEV), <a href="ch02.xhtml#page27">27</a></p>

С помощью page(\d+)">\1 мы сопоставляем page, за которым следует число, за которым следует ">, за которым следует тот же номер, что и в шаблоне в первой паре скобок (\1).

Функция подстановки принимает в качестве параметра совпадение. Итак, мы берем первую группу совпадения (m.group(1)), которая является числом, анализируем ее и уменьшаем на единицу. Затем мы реконструируем новую строку, используя уменьшенное число.

person JuniorCompressor    schedule 07.04.2015
comment
Возможно, было бы неплохо предоставить немного больше объяснений, вместо того, чтобы встраивать все и оставлять OP, чтобы просмотреть его ... тем не менее, мне нравится универсальный подход к замене обоих значений. - person jonrsharpe; 08.04.2015
comment
Спасибо @jonrsharpe за отзыв - person JuniorCompressor; 08.04.2015
comment
Спасибо, сама бы не догадалась! Я смог включить ваш код в свой, чтобы он анализировал xml построчно и выплевывал его как новый файл. - person John Gayle; 10.04.2015
comment
@JohnGayle он должен работать со всем xml, а не построчно ... если это не так, возможно, потребуется настройка - person JuniorCompressor; 11.04.2015
comment
@JuniorCompressor Это код, который у меня получился p = re.sub(r'page(\d+)">\1', lambda m: 'page{0}">{0}'.format(int(m.group(1)) - 1), line.rstrip()) Затем я записываю результаты в текстовый файл. - person John Gayle; 13.04.2015

Обратите внимание, что вы можете передать функцию в качестве аргумента repl в re.sub, которому будет передан один объект match "для каждого непересекающегося вхождения pattern":

def decrement(match):
    """Decrement the number in the match."""
    return str(int(match.group()) - 1)

Обратите внимание, что ожидается, что match.group() будет представлять целое число; чтобы зафиксировать только число, а не включать > и <, используйте обходные пути (см. демонстрацию):

page_num = re.compile(r'''
    (?<=>) # a > before the group
    \d+    # followed by one or more digits
    (?=<)  # and a < after the group
''', re.VERBOSE)

Это работает так, как вам нужно:

>>> page_num.sub(decrement, line)
'<p class="index">breakeven volume (BEV), <a href="ch02.xhtml#page28">27</a></p>'

и может применяться аналогичным образом для '#page28"'.

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

person jonrsharpe    schedule 07.04.2015
comment
Аргумент step= бесполезен, так как его абсолютно невозможно предоставить. Если бы вы действительно этого хотели, вы могли бы сделать: def decrementer(step=1): return lambda match: str(int(match.group()) - step), а затем page_num.sub(decrementer(), line) или page_num.sub(decrementer(2), line). - person Matt; 08.04.2015
comment
@Matt, есть два способа предоставить его: с помощью functools.partial или lambda. При этом я думаю, что ваш подход (помимо использования lambda) более аккуратен. - person jonrsharpe; 08.04.2015
comment
В этот момент было бы проще встроить всю функцию как лямбду. Или вы могли бы сделать то, что я сделал. - person Matt; 08.04.2015
comment
Кстати, я хотел бы дать вам второй +1 за упоминание о том, что HTML не является обычным языком. Хотя кажется, что в этом случае ОП имеет ограниченный набор данных, в котором регулярные выражения выполнят работу быстрее, не решая проблему для общего случая. - person Matt; 08.04.2015
comment
@Matt Я думаю, что часто именно поэтому люди в конечном итоге анализируют HTML с помощью регулярных выражений - это кажется проще для ограниченного набора, с которого они начинают, но неизбежно возникают пограничные случаи, и выражения становятся более сложными, и тогда им, вероятно, было бы лучше стиснуть зубы и правильно разобрать для начала! - person jonrsharpe; 08.04.2015