Удалить все символы в многострочной строке до заданного шаблона - PullRequest
3 голосов
/ 17 апреля 2010

При использовании Python мне нужно удалить все символы в многострочной строке до первого появления данного шаблона. В Perl это можно сделать с помощью регулярных выражений, например:

#remove all chars up to first occurrence of cat or dog or rat
$pattern = 'cat|dog|rat' 
$pagetext =~ s/(.*?)($pattern)/$2/xms; 

Какой лучший способ сделать это в Python?

Ответы [ 5 ]

5 голосов
/ 17 апреля 2010
>>> import re
>>> s = 'hello cat!'
>>> m = re.search('cat|dog|rat', s)
>>> s[m.start():]
'cat!'

Конечно, вам нужно учитывать случай, когда в реальном решении нет совпадения.

Или, более чисто:

>>> import re
>>> s = 'hello cat!'
>>> p = 'cat|dog|rat'
>>> re.sub('.*?(?=%s)' % p, '', s, 1)
'cat!'

Для мультилинии используйте флаг re.DOTALL.

4 голосов
/ 17 апреля 2010

Вы хотите удалить все символы, предшествующие первому вхождению шаблона; в качестве примера вы приводите «кошка | собака | крыса».

Код, который достигает этого, используя re:

re.sub("(?s).*?(cat|dog|rat)", "\\1", input_text, 1)

или, если вы снова будете использовать это регулярное выражение:

rex= re.compile("(?s).*?(cat|dog|rat)")
result= rex.sub("\\1", input_text, 1)

Обратите внимание на не жадных .*?. Начальный (?s) также позволяет сопоставлять символы новой строки перед соответствием слова.

Примеры:

>>> input_text= "I have a dog and a cat"
>>> re.sub(".*?(cat|dog|rat)", "\\1", input_text, 1)
'dog and a cat'

>>> re.sub("(?s).*?(cat|dog|rat)", "\\1", input_text, 1)
'I have no animals!'

>>> input_text= "This is irrational"
>>> re.sub("(?s).*?(cat|dog|rat)", "\\1", input_text, 1)
'rational'

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

>>> re.sub(r"(?s).*?\b(cat|dog|rat)\b", "\\1", input_text, 1)
'This is irrational'
2 голосов
/ 17 апреля 2010

без регулярных выражений

>>> s='hello cat!'
>>> pat=['cat','dog','rat']
>>> for n,i in enumerate(pat):
...     m=s.find(i)
...     if m != -1: print s[m:]
...
cat!
1 голос
/ 17 апреля 2010

Что-то вроде этого должно делать то, что вы хотите:

import re
text = '   sdfda  faf foo zing baz bar'
match = re.search('foo|bar', text)
if match:
  print text[match.start():] # ==>  'foo zing baz bar'
0 голосов
/ 18 апреля 2010

Другим вариантом является использование вида вперед s/.*?(?=$pattern)//xs:

re.sub(r'(?s).*?(?=cat|dog|rat)', '', text, 1)

Путь без регулярных выражений:

for option in 'cat dog rat'.split():
    index = text.find(option)
    if index != -1: # found
       text = text[index:]
       break

Способ без регулярных выражений почти в 5 раз быстрее (для некоторого ввода):

$ python -mtimeit -s'from drop_until_word import drop_re, text, options;' \
> 'drop_re(text, options)'
1000 loops, best of 3: 1.06 msec per loop

$ python -mtimeit -s'from drop_until_word import drop_search, text, options;'\
> 'drop_search(text, options)'
10000 loops, best of 3: 184 usec per loop

$ python -mtimeit -s'from drop_until_word import drop_find, text, options;' \
> 'drop_find(text, options)'
1000 loops, best of 3: 207 usec per loop

Где drop_until_word.py:

import re

def drop_re(text, options):
    return re.sub(r'(?s).*?(?='+'|'.join(map(re.escape, options))+')', '',
                  text, 1)

def drop_re2(text, options):
    return re.sub(r'(?s).*?('+'|'.join(map(re.escape, options))+')', '\\1',
                  text, 1)

def drop_search(text, options):
    m = re.search('|'.join(map(re.escape, options)), text)
    return text[m.start():] if m else text

def drop_find(text, options):
    indexes = [i for i in (text.find(option) for option in options) if i != -1]
    return text[min(indexes):] if indexes else text

text = open('/usr/share/dict/words').read()
options = 'cat dog rat'.split()

def test():
    assert drop_find(text, options) == drop_re(text, options) \
        == drop_re2(text, options) == drop_search(text, options)

    txt = 'dog before cat'
    r = txt
    for f in [drop_find, drop_re, drop_re2, drop_search]:
        assert r == f(txt, options), f.__name__


if __name__=="__main__":
    test()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...