2015-10-29 3 views
3

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

"foo hello world baz 33" 

часть между foo и baz будет некоторое количество разделенных пробелами слов (одного или нескольких). Я хочу, чтобы соответствовать этой строке с повторным, что будет группа из каждых из этих слов:

>>> re.match(r'foo (<some re here>) baz (\d+)', "foo hello world baz 33").groups() 
('hello', 'world', '33') 

Повторно должна быть гибкой, так что он будет работать в случае, если нет слова вокруг него:

>>> re.match(r'(<some re here>)', "hello world").groups() 
('hello', 'world') 

Я пытаюсь варианты с ([\w+\s])+, но я не могу захватить динамически определенное количество групп. Это возможно?

+0

Вы будете нуждаться в 're.findall' и 3, захватив группы:' re.findall (г '^ Foo (\ S +) (\ S +) Баз (\ d +)', ' foo hello world baz 33 ') '. См. [Demo] (https://ideone.com/rAWt3I). –

+0

Это не сработает. Здесь может быть любое количество слов. Так что «foo hello hello hello baz 33» не будет соответствовать – Neil

+0

Не проблема, я обновил [код] (https://ideone.com/rAWt3I). Регулярное выражение может быть «r»^foo (\ S + (?: \ S + \ S +) *) (\ S +) baz (\ d +) ''. Или вы хотите, чтобы слова в первой группе захвата были разделены? Тогда это невозможно без дополнительных операций. Просто регулярное выражение не будет делать. –

ответ

8

re.match возвращает результат в начале строки. Вместо этого используйте re.search.
.*? возвращает кратчайшее совпадение между двумя словами/выражениями (означает что-либо, * означает 0 или более вхождений и? Означает кратчайшее совпадение).

import re 
my_str = "foo hello world baz 33" 
my_pattern = r'foo\s(.*?)\sbaz' 
p = re.search(my_pattern,my_str,re.I) 
result = p.group(1).split() 
print result 

['hello', 'world'] 

EDIT:

В случае обув или Баз отсутствует, и вы должны вернуть всю строку, используйте if-else:

if p is not None: 
    result = p.group(1).split() 
else: 
    result = my_str 

Почему ? в схеме:
Предположим, что существует несколько вхождений слова baz:

my_str = "foo hello world baz 33 there is another baz" 

использованием pattern = 'foo\s(.*)\sbaz' будет соответствовать (длинный и жадный):

'hello world baz 33 there is another' 

тогда, используя pattern = 'foo\s(.*?)\sbaz' вернет самый короткий матч:

'hello world' 
+0

Группы, не связанные с захватом, не нужны и должны быть удалены. Помимо этого, это, вероятно, лучшее решение. Возможно, добавьте что-то для учета '33' в конце. –

+0

OP запросил матч между foo и bar в комментариях к вопросу. Спасибо за ваши отзывы, внесут изменения :) –

+0

Да, спецификации немного туманны. :) –

-2

Не знаю. Я хотел бы использовать что-то на линии:

(?<=foo (\w+\s)*)(\w+\s)(?=(\w+\s)*baz \d+) 

найти Foo-и-некоторые-слова-предшествуют слово, которое сопровождается некоторыми словами, Баз, и некоторые цифры. Затем, вместо использования групп, я бы выполнил несколько находок, используя один и тот же набор. (Я не использовал регулярные выражения Python (regexen?), Так что, возможно, это не применимо. Оно должно работать на Java.)

EDIT: @TimP Я не знал, что утверждения о взгляде должны были иметь определенную длину , Спасибо за совет.

Думая об этом более внимательно, я бы этого не сделал, но (если вообще возможно), я бы разделил его на две фазы: сначала я захватил слова (с помощью «foo ((?: \ w + \ s) +) bar (\ d +) 'возможно), а затем я бы использовал другое регулярное выражение для просмотра захваченного текста.

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

+0

Это даже не компилируется в Java (и это тоже не работает на Python).Утверждения Lookbehind не могут быть неопределенной длины на любом из двух языков. –

2

[Это не решение, но я стараюсь объяснить, почему это невозможно]

Что вам нужно? ING как этого:

foo\s(\w+\s)+baz\s(\d+) 

Прохладная часть будет (\w+\s)+, что бы повторить группу захвата. Проблема в том, что большинство ароматизаторов регулярных выражений сохраняют только последнее совпадение в этой группе захвата; старые записи перезаписываются.

Я рекомендую перебрать строку с более простым регулярным выражением.

Надеется, что это помогает

+0

Связанный вопрос с похожим ответом здесь: [link] (http://stackoverflow.com/questions/3537878/how-to-capture-an-arbitrary-number-of-groups-in-javascript-regexp) –

0

использованию index найти foo и baz. затем split суб строка

def find_between(s, first, last): 
    try: 
     start = s.index(first) + len(first) 
     end = s.index(last, start) 
     return s[start:end].split() 
    except ValueError: 
     return "" 

s = "foo hello world baz 33" 
start = "foo" 
end = "baz" 
print find_between(s,start,end) 
Смежные вопросы