2015-09-24 2 views
1

У меня есть следующий повторно извлечь MAC-адрес:Python Regex соответствует MAC-адресу с конца?

re.sub(r'(\S{2,2})(?!$)\s*', r'\1:', '0x0000000000aa bb ccdd ee ff') 

Однако это дало мне 0x:00:00:00:00:00:aa:bb:cc:dd:ee:ff.

Как изменить это регулярное выражение для остановки после согласования первых 6 пар, начиная с конца, так что я получаю aa:bb:cc:dd:ee:ff?

Примечание: в строке есть пробел между которыми следует игнорировать. Нужны только последние 12 символов.

Редактировать 1:re.findall(r'(\S{2})\s*(\S{2})\s*(\S{2})\s*(\S{2})\s*(\S{2})\s*(\S{2})\s*$',a) находит последние 6 пар в строке. Я до сих пор не знаю, как сжать это регулярное выражение. Опять же это все еще зависит от того, что строки находятся в парах.

В идеале регулярное выражение должно взять последние 12 действительных \S символов, начиная с конца и нанизывают с :

Edit2: Вдохновленный @Mariano ответ, который прекрасно работает, но зависит от того, что что последние 12 символов должен начинаться с пары. Я придумал следующее решение. Это kludgy, но все же, похоже, работает на все входы.

string = '0x0000000000a abb ccddeeff' 
':'.join(''.join(i) for i in re.findall('(\S)\s*(\S)(?!(?:\s*\S\s*{11})',' string)) 
'aa:bb:cc:dd:ee:ff' 

Edit3: @Mariano обновил свой ответ, который в настоящее время работает для всех входов

+2

знак доллара, '$', представляет собой конец линии. Используйте это, чтобы выразить, что после 6 матчей вы хотите, чтобы линия заканчивалась. – Javier

ответ

2

Это будет работать в течение последних 12 символов, игнорируя пробелы ,

Код:

import re 

text = "0x0000000000aa bb ccdd ee ff" 

result = re.sub(r'.*?(?!(?:\s*\S){13})(\S)\s*(\S)', r':\1\2', text)[1:] 

print(result) 

Выход:

aa:bb:cc:dd:ee:ff 

DEMO


Regex пробоя:

Выражение, используемое в этом коде используется re.sub() заменить следующие в теме текста:

.*?     # consume the subject text as few as possible 
(?!(?:\s*\S){13}) # CONDITION: Can't be followed by 13 chars 
        # so it can only start matching when there are 12 to $ 
(\S)\s*(\S)   # Capture a char in group 1, next char in group 2 
        # 
    # The match is replaced with :\1\2 
    # For this example, re.sub() returns ":aa:bb:cc:dd:ee:ff" 
    # We'll then apply [1:] to the returned value to discard the leading ":" 
+0

Это работает! можете ли вы добавить краткое объяснение того, что делает ре? – user881300

+0

только что заметил, что мы все еще зависим от того, что строка 12,11 с конца должна быть в парах. – user881300

+0

'':'. Join ('.join (i) для i в re.findall (' (\ S) \ s * (\ S) (?! (?: \ S * \ S \ s *) { 11}) ',' 0x0000000000aabb ccddeeff ')) ', похоже, работает для любого ввода – user881300

0

Вы можете сделать так,

>>> import re 
>>> s = '0x0000000000aa bb ccdd ee ff' 
>>> re.sub(r'(?!^)\s*(?=(?:\s*[a-z]{2})+$)', ':', re.sub(r'.*?((?:\s*[a-z]){12})\s*$', r'\1', s)) 
'aa:bb:cc:dd:ee:ff' 
>>> s = '???767aa bb ccdd ee ff' 
>>> re.sub(r'(?!^)\s*(?=(?:\s*[a-z]{2})+$)', ':', re.sub(r'.*?((?:\s*[a-z]){12})\s*$', r'\1', s)) 
'aa:bb:cc:dd:ee:ff' 
>>> s = '???767aa bb ccdd eeff ' 
>>> re.sub(r'(?!^)\s*(?=(?:\s*[a-z]{2})+$)', ':', re.sub(r'.*?((?:\s*[a-z]){12})\s*$', r'\1', s)) 
'aa:bb:cc:dd:ee:ff' 
0

Я знаю, что это не является прямым ответом на ваш вопрос, но вам действительно нужно регулярное выражение? Если ваш формат фиксировано, это также должно работать:

>>> s = '0x0000000000aa bb ccdd ee ff' 
>>> ':'.join([s[-16:-8].replace(' ', ':'), s[-8:].replace(' ', ':')]) 
'aa:bb:cc:dd:ee:ff' 
1

Вы можете использовать re.finditer, чтобы найти все пары затем присоединиться к результату:

>>> my_string='0x0000000000aa bb ccdd ee ff' 
>>> ':'.join([i.group() for i in re.finditer(r'([a-z])\1+',my_string)]) 
'aa:bb:cc:dd:ee:ff' 
+1

должны соответствовать только последние 12 символов. Это будет соответствовать любым парам [a-z], например: '0x0000000000zzaa bb ccdd ee ff'' zz' следует игнорировать – user881300

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