Захватите содержимое регулярного выражения и удалите его эффективно

Ситуация:

  • текст: строка
  • R: регулярное выражение, которое соответствует части строки. Подсчитать это может быть дорого.

Я хочу как удалить R-совпадения из текста, так и посмотреть, что они на самом деле содержат. Сейчас мне нравится:

import re
ab_re = re.compile("[ab]")
text = "abcdedfe falijbijie bbbb laifsjelifjl"
ab_re.findall(text)
# ['a', 'b', 'a', 'b', 'b', 'b', 'b', 'b', 'a']
ab_re.sub('',text)
# 'cdedfe flijijie  lifsjelifjl'

Это запускает регулярное выражение дважды, насколько я могу судить. Есть ли способ сделать все это на ходу, возможно, используя re.split? Похоже, что с решениями на основе разделения мне нужно было бы выполнять регулярное выражение как минимум дважды.

По крайней мере, 3 хороших набора ответов. Мой быстрый и простой, с использованием re.split (). Deestan предоставляет всю информацию о совпадениях с помощью finditer (), а Jon Cage показывает, что функции могут использоваться в re.sub, что является умным.

Gregg Lind 17.10.2008 03:26
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
7
1
258
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете использовать разделение с захватом скобок. Если вы это сделаете, то текст всех групп в шаблоне также будет возвращен как часть результирующего списка (из Документ Python).

Итак, код будет

import re
ab_re = re.compile("([ab])")
text = "abcdedfe falijbijie bbbb laifsjelifjl"
matches = ab_re.split(text)
# matches = ['', 'a', '', 'b', 'cdedfe f', 'a', 'lij', 'b', 'ijie ', 'b', '', 'b', '', 'b', '', 'b', ' l', 'a', 'ifsjelifjl']

# now extract the matches
Rmatches = []
remaining = []
for i in range(1, len(matches), 2):
    Rmatches.append(matches[i])
# Rmatches = ['a', 'b', 'a', 'b', 'b', 'b', 'b', 'b', 'a']

for i in range(0, len(matches), 2):
    remaining.append(matches[i])
remainingtext = ''.join(remaining)
# remainingtext = 'cdedfe flijijie  lifsjelifjl'

Весь код if text == a здесь реализует регулярное выражение во второй раз. Если бы регулярное выражение было простым, как [ab], тогда весь этот вопрос был бы спорным. :) Хорошие усилия, и это немного подтолкнуло меня к размышлениям о решениях для фильтрации.

Gregg Lind 15.10.2008 18:50

Да, исправил это, заметив, что совпадения имеют чередующееся совпадение и отброшенный текст, включая пустые строки, поэтому приведенное выше решение проще, а регулярное выражение запускается только один раз :)

Hamish Downer 15.10.2008 18:54

Справедливо. Однако нарезка проще :) У меня тоже было такое же представление о чередовании совпадения токенов! Спасибо за подсказку.

Gregg Lind 15.10.2008 19:02
Ответ принят как подходящий

import re

r = re.compile("[ab]")
text = "abcdedfe falijbijie bbbb laifsjelifjl"

matches = []
replaced = []
pos = 0
for m in r.finditer(text):
    matches.append(m.group(0))
    replaced.append(text[pos:m.start()])
    pos = m.end()
replaced.append(text[pos:])

print matches
print ''.join(replaced)

Выходы:

['a', 'b', 'a', 'b', 'b', 'b', 'b', 'b', 'a']
cdedfe flijijie  lifsjelifjl

Вы можете использовать список вместо StringIO и присоединиться к нему в конце, если хотите, чтобы он был простым.

Tomalak 15.10.2008 18:50

Томалак: Да, было бы проще. Немного тестового профилирования показывает, что он на самом деле быстрее, по крайней мере, на моем тестовом входе.

Deestan 15.10.2008 19:08

Меня не особо удивляет. Я набирал по сути то же самое, просто ты оказался быстрее. ;-)

Tomalak 16.10.2008 16:05

Мой пересмотренный ответ с использованием re.split (), который делает что-то за один проход регулярного выражения:

import re
text = "abcdedfe falijbijie bbbb laifsjelifjl"
ab_re = re.compile("([ab])")
tokens = ab_re.split(text)
non_matches = tokens[0::2]
matches = tokens[1::2]

(изменить: вот полная версия функции)

def split_matches(text,compiled_re):
    ''' given  a compiled re, split a text 
    into matching and nonmatching sections
    returns m, n_m, two lists
    '''
    tokens = compiled_re.split(text)
    matches = tokens[1::2]
    non_matches = tokens[0::2]
    return matches,non_matches

m,nm = split_matches(text,ab_re)
''.join(nm) # equivalent to ab_re.sub('',text)

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

Gregg Lind 15.10.2008 19:38

Хм? У меня работает без скобок.

Deestan 17.10.2008 11:33

Как насчет этого:

import re

text = "abcdedfe falijbijie bbbb laifsjelifjl"
matches = []

ab_re = re.compile( "[ab]" )

def verboseTest( m ):
    matches.append( m.group(0) )
    return ''

textWithoutMatches = ab_re.sub( verboseTest, text )

print matches
# ['a', 'b', 'a', 'b', 'b', 'b', 'b', 'b', 'a']
print textWithoutMatches
# cdedfe flijijie  lifsjelifjl

Аргумент «repl» функции re.sub может быть функцией, чтобы вы могли сообщать или сохранять совпадения оттуда, и все, что возвращает функция, заменяет «sub».

Функцию можно легко изменить, чтобы делать гораздо больше! Ознакомьтесь с документация по модулю re на docs.python.org для получения дополнительной информации о том, что еще возможно.

Это очень умное решение. Я не знал, что вы можете использовать функции в качестве первого аргумента подфункции.

Gregg Lind 15.10.2008 19:16

Спасибо, меня поразила его простота, когда я понял, что вы можете вызвать функцию :-)

Jon Cage 15.10.2008 20:57

Другие вопросы по теме