Почему первое чередование не совпадает?

У меня есть следующее регулярное выражение (Python), которое я не понимаю в следующем пункте. Почему оно не соответствует первому чередованию?

Regex (для лучшего понимания):

(?:
  \$\{
    (?P<braced>
       [_a-zA-Z][a-zA-Z0-9]*(?::[_a-zA-Z][_a-zA-Z0-9]*)+
    )
  \}
)
|   ### SECOND ALTERNATION ###
(?:
  \$
   (?P<named>
     [_a-zA-Z][a-zA-Z0-9]*(?::[_a-zA-Z][_a-zA-Z0-9]*)+
   )
)

Тестовая строка:

asdasd $ asd: sd + $ {asd123: asd} $ HOME $$ asd

Подходящие вещи:

asdasd $ asd: sd + $ {asd123: asd} $ HOME $$ asd

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

${asd123:asd}

Кажется, я не совсем понимаю шаблон чередования?

3 ответа

Решение

Для того, чтобы захватить ${...}нужно удалить ?: превратить не захватывающие группы в захватывающие. Вы также можете сделать их именными. Также [_a-zA-Z0-9] равно \ w, поэтому мы можем немного сократить ваше регулярное выражение:

(?P<Alternation1>
 \$\{(?P<braced>[_a-zA-Z][a-zA-Z0-9]*(?::[_a-zA-Z]\w*)+)
 \}
 )
 |
 (?P<Alternation2>
  \$(?P<named>[_a-zA-Z][a-zA-Z0-9]*(?::[_a-zA-Z]\w*)+
 )
)

Посмотрите на демо. Это регулярное выражение требует использования x вариант (и g опции на regex101.com, чтобы показать все совпадения, в Python вы бы использовали findall или же finditer).

Дополнительную информацию о группах без захвата можно получить на SO и по адресу регулярно-expressions.info.

Чтобы просто получить все совпадения в Python, вы можете использовать finditer как это:

import re
p = re.compile(ur'''(?P<Alternation1>
     \$\{(?P<braced>[_a-zA-Z][a-zA-Z0-9]*(?::[_a-zA-Z]\w*)+)
     \}
     )
     |
     (?P<Alternation2>
      \$(?P<named>[_a-zA-Z][a-zA-Z0-9]*(?::[_a-zA-Z]\w*)+
     )
    )
''', re.VERBOSE)
test_str = u"asdasd $asd:sd + ${asd123:asd} $HOME $$asd"

print [x for x in re.findall(p, test_str)]

Посмотреть демо IDEONE

Вам нужно добавить g модификатор, чтобы получить все совпадения на regex101.com

https://www.regex101.com/r/nP8pK0/1

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

>>> for m in re.finditer(pattern, text):
...     print 'whole match: %s' (m.group(0))
...     print 'group "braced": %s' % (m.group('braced'))
...     print 'group "named": %s\n' % (m.group('named'))

(Проблема с findall (который также выполняет глобальное исследование) в том, что когда в шаблоне есть группы захвата, результат содержит только список содержимого групп захвата, а не весь результат сопоставления. Так что объединение всех в группу захвата, как предложил Стрибижев, может быть способом findall).

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