Вопрос регулярного выражения Python - PullRequest
2 голосов

Ответы [ 2 ]

3 голосов
/ 01 октября 2009

Вот мое решение Python.

import re
pat = re.compile("^(\D+)(\d+)(.*)$")

def rle_expand(s):
    lst = []
    while True:
        m = pat.match(s)
        if m:
            n = int(m.group(2))
            lst.append(m.group(1) * n)
        else:
            lst.append(s)
            break
        s = m.group(3)
    return "".join(lst)

s = "aa03bc05d9whew"

print rle_expand(s)
# prints aaaaaabcbcbcbcbcdddddddddwhew

s = “aa67bc54c9”
print rle_expand(s)
# prints: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcccccccccc   

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

Сначала мы импортируем модуль re, чтобы получить доступ к регулярным выражениям Python.

Далее мы скомпилируем шаблон один раз, чтобы мы могли использовать его позже. Что будет делать этот шаблон?

Шаблон использует круглые скобки, чтобы пометить группы букв из сопоставляемой строки. Есть три пары паренов, так что это будет соответствовать трем группам. Перед первой группой стоит символ «^», который привязывается к началу строки, а после последней группы - символ «$», который привязывается к концу строки; в этом случае это не обязательно. Первая группа соответствует всему, что является , а не цифрой, используя специальную последовательность \D; + расширяет его, чтобы он соответствовал серии из одного или нескольких экземпляров без цифр. Вторая группа похожа, используя \d+, чтобы соответствовать серии из одной или нескольких цифр. Третья группа использует . для сопоставления с любым символом, а затем расширяет его до * для сопоставления с 0 или более символами. (Обратите внимание, что * и + очень похожи; просто * соответствует 0 или более чем-то, а + соответствует одному или нескольким.)

Используя стандартную идиому Python, мы строим строку, используя список. Мы начинаем с пустого списка (называемого lst). Пока шаблон продолжает соответствовать, мы добавляем элементы в этот список. Когда мы закончим, мы используем "".join(), чтобы объединить список в строку.

pat.match() возвращает объект, называемый «объектом сопоставления», или None, если сопоставление не удалось. Если совпадение выполнено успешно, мы преобразуем группу совпадений 2 в целое число и используем оператор повторения строк Python («multiply») в группе совпадений 1, чтобы выполнить расширение по длине прогона. После этого мы связываем имя s с результатами группы совпадений 3, отсекая часть только что обработанной строки, и выполняем цикл. Если совпадение не удалось, мы просто добавляем все s в список и вырываемся из цикла.

Создание списка с последующим использованием "".join() в списке - это стандартная идиома Python. Это даст хорошую производительность с любой версией Python. Поскольку строки Python являются неизменяемыми, вы можете страдать от очень низкой производительности, если создаете длинную динамическую строку, многократно добавляя строку; Вы копируете ранние части строки много раз, когда строите свою последнюю строку. К спискам Python можно добавить тривиальные данные, а затем завершающая операция соединения выполняется довольно быстро. (Последние версии Python оптимизировали случай, когда вы неоднократно добавляете строку, и больше не страдаете от повторного копирования в этом случае.)

Решение Грега Хьюгилла распознает только строчные буквы от «а» до «z» для текста расширения; это можно исправить, поставив \D вместо [a-z]. Его решение использует явные диапазоны, такие как [0-9], где мое решение использует сокращенные сокращения Python, такие как \d. Его решение расширяет только кодированные последовательности длин серий; если есть конечная последовательность, в которой нет целого числа, мой пропускает эту последовательность без изменений, в то время как он молча игнорирует ее. Тем не менее, следует сказать, что его решение жестоко изящно, и я бы хотел подумать об этом. : -)

3 голосов
/ 01 октября 2009

Это был бы краткий путь:

import re

s = "aa67bc54c9"
print ''.join(t * int(n) for t, n in re.findall(r"([a-z]+)([0-9]+)", s))

В этом решении используется регулярное выражение для сопоставления «одной или нескольких букв, за которыми следует одно или несколько чисел», при поиске всех их во входной строке. Затем он использует понимание списка, чтобы перебрать каждую найденную группу, присваивая буквы t, а цифры - n по очереди. Список генерирует строки, используя оператор строки *, который повторяет строку заданное число раз (int() используется для преобразования строки цифр в целое число). Наконец, ''.join() используется для вставки всего вместе.

Для регулярного выражения [a-z] является классом символов, состоящим из одной (строчной) буквы алфавита. [a-z]+ означает одну или несколько строчных букв. Точно так же [0-9]+ означает одну или несколько цифр. Группирующие скобки вокруг каждого компонента «захватывают» символы внутри них и делают их доступными в результате использования функции findall(). Есть две группы круглых скобок, поэтому есть два выходных значения, которые присваиваются t и n в понимании списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...