2014-09-02 2 views
4

Когда я пытался ответить на этот вопрос: regex to split %ages and values in python Я заметил, что мне пришлось переупорядочить группы из результата findall. Например:Захват названных групп в regex с re.findall

data = """34% passed 23% failed 46% deferred""" 
result = {key:value for value, key in re.findall('(\w+)%\s(\w+)', data)} 
print(result) 
>>> {'failed': '23', 'passed': '34', 'deferred': '46'} 

Вот результат FindAll является:

>>> re.findall('(\w+)%\s(\w+)', data) 
>>> [('34', 'passed'), ('23', 'failed'), ('46', 'deferred')] 

Есть ли способ изменить/задать порядок групп, что делает re.findall вернуться:

[('passed', '34'), ('failed', '23'), ('deferred', '46')] 

Просто чтобы прояснить, вопрос:

ли возможно ли уточнить порядок или переупорядочить группы для возврата функции re.findall?

Я использовал пример выше, чтобы создать словарь, чтобы обеспечить причина/случай использования, когда вы хотели бы изменить порядок (изготовление ключа в качестве значения и значения в качестве ключа)

Дальнейшее уточнение:

Чтобы обрабатывать группы в более сложных более сложных регулярных выражениях, вы можете назвать группы, но эти имена доступны, только если вы выполните re.search pr re.match. Из того, что я прочитал, findall имеет фиксированные индексы для групп, возвращаемых в кортеж. Вопрос: кто-нибудь знает, как эти индексы могут быть изменены. Это поможет упростить и интуитивно понятное управление группами.

+1

Это ** не ** можно изменить порядок групп, возвращенных 'findAll', но это легко изменить порядок их после того, как тот факт, как я показал в своем втором ответе: http://stackoverflow.com/a/25629693/20789 –

+0

То, что я предполагал, но не смог найти документацию, чтобы заявить об этом. Отсюда мой вопрос. – ashwinjv

ответ

3

Возьмите 3, основываясь на дальнейшем уточнении намерения OP в this comment.

Ashwin прав, что findall не сохраняет именованные группы захвата (например, (?P<name>regex)). finditer на помощь! Он возвращает отдельные совпадающие объекты один за другим. Простой пример:

data = """34% passed 23% failed 46% deferred""" 
for m in re.finditer('(?P<percentage>\w+)%\s(?P<word>\w+)', data): 
    print(m.group('percentage'), m.group('word')) 
0

Как вы определили в своем втором примере, re.findall возвращает группы в первоначальном порядке.

Проблема заключается в том, что стандартный тип Python dict не сохраняет порядок ключей в любом случае. Вот руководство для Python 2.x, что делает его явным, но это все-таки правда в Python 3.x: https://docs.python.org/2/library/stdtypes.html#dict.items

То, что вы должны использовать вместо этого collections.OrderedDict:

from collections import OrderedDict as odict 

data = """34% passed 23% failed 46% deferred""" 
result = odict((key,value) for value, key in re.findall('(\w+)%\s(\w+)', data)) 
print(result) 
>>> OrderedDict([('passed', '34'), ('failed', '23'), ('deferred', '46')]) 

Обратите внимание, что вы должны использовать парный конструктор (dict((k,v) for k,v in ...), а не конструктор понимания dict ({k:v for k,v in ...}). Это потому, что последний строит экземпляры типа dict, которые не могут быть преобразованы в OrderedDict, не теряя при этом порядок ключей ... что, конечно же, вы пытаетесь сохранить в первую очередь.

+0

Мне было интересно, могу ли я указать или изменить исходный порядок возврата для re.findall. Преобразование в dict было всего лишь примером того, когда я хочу переупорядочить группы. – ashwinjv

+0

Ваш вопрос не дает понять, что вы пытаетесь переупорядочить. Пожалуйста, отредактируйте его, чтобы уточнить это. –

0

Per the OP's comment on my first answer: Если вы просто пытаетесь изменить порядок список 2-кортежей, как это:

[('34', 'passed'), ('23', 'failed'), ('46', 'deferred')] 

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

[('passed', '34'), ('failed', '23'), ('deferred', '46')] 

Там легкое решение: использовать список понимание с нарезанием синтаксисом sequence[::-1], чтобы изменить порядок элементов отдельных кортежей:

a = [('34', 'passed'), ('23', 'failed'), ('46', 'deferred')] 
b = [x[::-1] for x in a] 
print b 
+0

Я знаю, как переупорядочить кортежи, вопросы касаются конкретного порядка re.findall. – ashwinjv

+0

Порядок ** какой ** 're-findall'? Я покажу вам, как взять вывод 're.findall' и изменить его, чтобы получить заказ, который вы сказали. –

+1

Чтобы обрабатывать группы в более сложных более сложных регулярных выражениях, вы можете назвать группы, но эти имена доступны, только если вы выполните re.search pr re.match. Из того, что я прочитал, findall имеет фиксированные индексы для групп, возвращаемых в кортеж. Вопрос: кто-нибудь знает, как эти индексы могут быть изменены. Это поможет упростить и интуитивно понятное управление группами. – ashwinjv

Смежные вопросы