строковая маска и смещение с помощью регулярного выражения - PullRequest
3 голосов
/ 18 июля 2010

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

"The quick, brown fox jumps over the lazy dog."

Я хочу показать 3 слова одновременно:

смещение 0: "The quick, brown"
смещение 1: "quick, brown fox"
смещение 2: "brown fox jumps"
смещение 3: "fox jumps over"
смещение 4: "jumps over the"
смещение 5: "over the lazy"
смещение 6: "the lazy dog."

Я использую Python и использую следующее простое регулярное выражение для обнаружения 3 слов:

>>> import re
>>> s = "The quick, brown fox jumps over the lazy dog."
>>> re.search(r'(\w+\W*){3}', s).group()
'The quick, brown '

Но я не могу понять, как создать маску для отображения следующих 3 слов, а не начальных.Мне нужно сохранить пунктуацию.

Ответы [ 4 ]

5 голосов
/ 18 июля 2010

Параметр сопоставления префиксов

Эту работу можно выполнить, используя регулярное выражение переменной-префикса для пропуска первых offset слов и захвата триплета слова в группу.

Так что-то вроде этого:

import re
s = "The quick, brown fox jumps over the lazy dog."

print re.search(r'(?:\w+\W*){0}((?:\w+\W*){3})', s).group(1)
# The quick, brown 
print re.search(r'(?:\w+\W*){1}((?:\w+\W*){3})', s).group(1)
# quick, brown fox      
print re.search(r'(?:\w+\W*){2}((?:\w+\W*){3})', s).group(1)
# brown fox jumps 

Давайте посмотрим на шаблон:

 _"word"_      _"word"_
/        \    /        \
(?:\w+\W*){2}((?:\w+\W*){3})
             \_____________/
                group 1

Это делает то, что говорит: сопоставить 2 слова, затем захватить в группу 1, сопоставить3 слов.

Конструкции (?:...) используются для группировки для повторения, но они не захватывают.

Ссылки


Примечание к шаблону "word"

Следует сказать, что \w+\W* - плохой выбор для шаблона "word", как показано в следующем примере:

import re
s = "nothing"
print re.search(r'(\w+\W*){3}', s).group()
# nothing

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

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

\w+(?:\W+|$)

То есть \w+, за которым следует либо \W+, либо конец строки $.


Опция перехвата захвата

Как предложил Коби в комментарии, эта опция проще в том, что у вас есть только один статический шаблон.Он использует findall для захвата всех совпадений ( см. На ideone.com ):

import re
s = "The quick, brown fox jumps over the lazy dog."

triplets = re.findall(r"\b(?=((?:\w+(?:\W+|$)){3}))", s)

print triplets
# ['The quick, brown ', 'quick, brown fox ', 'brown fox jumps ',
#  'fox jumps over ', 'jumps over the ', 'over the lazy ', 'the lazy dog.']

print triplets[3]
# fox jumps over 

Как это работает, так как он совпадает на границе слова нулевой ширины \b, используяс нетерпением ждем 3 «слова» в группе 1.

    ______lookahead______
   /      ___"word"__    \
  /      /           \    \
\b(?=((?:\w+(?:\W+|$)){3}))
     \___________________/
           group 1

Ссылки

2 голосов
/ 18 июля 2010

Один наклон будет разделить строку и выбрать фрагменты:

words = re.split(r"\s+", s)
for i in range(len(words) - 2):
    print ' '.join(words[i:i+3])

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

1 голос
/ 18 июля 2010

У нас есть две ортогональные проблемы:

  1. Как разбить строку.
  2. Как построить группы из 3 последовательных элементов.

Для 1 вы можете использовать регулярные выражения или - как уже указывали другие - достаточно простого str.split.Для 2 обратите внимание, что вы хотите, чтобы выглядело очень похоже на pairwise абстракцию в рецептах itertools :

http://docs.python.org/library/itertools.html#recipes

Итак, мы пишем нашу обобщенную n-мудрую функцию:

import itertools

def nwise(iterable, n):
    """nwise(iter([1,2,3,4,5]), 3) -> (1,2,3), (2,3,4), (4,5,6)"""
    iterables = itertools.tee(iterable, n)
    slices = (itertools.islice(it, idx, None) for (idx, it) in enumerate(iterables))
    return itertools.izip(*slices)

И мы получаем простой и модульный код:

>>> s = "The quick, brown fox jumps over the lazy dog."
>>> list(nwise(s.split(), 3))
[('The', 'quick,', 'brown'), ('quick,', 'brown', 'fox'), ('brown', 'fox', 'jumps'), ('fox', 'jumps', 'over'), ('jumps', 'over', 'the'), ('over', 'the', 'lazy'), ('the', 'lazy', 'dog.')]

Или, как вы просили:

>>> # also: map(" ".join, nwise(s.split(), 3))
>>> [" ".join(words) for words in nwise(s.split(), 3)]
['The quick, brown', 'quick, brown fox', 'brown fox jumps', 'fox jumps over', 'jumps over the', 'over the lazy', 'the lazy dog.']
1 голос
/ 18 июля 2010

Нет необходимости в регулярных выражениях

>>> s = "The quick, brown fox jumps over the lazy dog."
>>> for offset in range(7):
...     print 'offset {0}: "{1}"'.format(offset, ' '.join(s.split()[offset:][:3]))
... 
offset 0: "The quick, brown"
offset 1: "quick, brown fox"
offset 2: "brown fox jumps"
offset 3: "fox jumps over"
offset 4: "jumps over the"
offset 5: "over the lazy"
offset 6: "the lazy dog."
...