Как сопоставить шаблон, содержащий неопределенное количество 2-значных шестнадцатеричных чисел, разделенных одним пробелом?

#python #regex

#python #регулярное выражение

Вопрос:

Сопоставьте шаблон, содержащий неопределенное количество 2-значных шестнадцатеричных чисел, разделенных одним пробелом.

 0000000: 4B 0B 69 00 04 00 00 00 EE 03 00 00 00 00 00 00  abcdefg
==> 4B 0B 69 00 04 00 00 00 EE 03 00 00 00 00 00 00

12345 4B 0B 69 00 04 00 00 00 EE 03 00 00   01 02
==> 4B 0B 69 00 04 00 00 00 EE 03 00 00

# (because there are more than one space between 00 and 01)

12: 4B 0B 69 00 04 00 00 00 EE 2
==> 4B 0B 69 00 04 00 00 00 EE

5 4B 0B 69 00 04 00 3
==> 4B 0B 69 00 04 00

ZZ 4B 0B 69 00 04 00 DD MN
==> 4B 0B 69 00 04 00 DD

# Because ZZ and MN are not hex numbers
  

Ответ №1:

Поиск сзади должен решить эту проблему. Вы ищете- b(?<! {2})([da-f]{2})(?= {1}) (с нечувствительным флагом)

Вот демо

Объяснение

 b(?<! {2})([da-f]{2})(?= {1})
  
  • b — соответствует границе слова, это в основном просто для того, чтобы убедиться, что он не соответствует таким вещам, как 45 из 12345 в 12345 4B 0B 69 00 04 00 00 00 EE 03 00 00 01 02
  • (?<! {2}) — это гарантирует, что совпадение не имеет 2 пробела слева
  • ([da-f]{2}) — фиксирует шестнадцатеричные числа из 2 цифр
  • (?= {1}) — После этого проверяется наличие единственного пробела

Код

В Python вы можете использовать флаг re.findall with re.I для поиска всех шестнадцатеричных чисел в заданной строке.

 import re

match = re.findall(r'b(?<! {2})([da-f]{2})(?= {1})', '0000000: 4B 0B 69 00 04 00 00 00 EE 03 00 00 00 00 00 00  abcdefg', flags=re.I)
print(match)
  

Вывод

 ['4B',
 '0B',
 '69',
 '00',
 '04',
 '00',
 '00',
 '00',
 'EE',
 '03',
 '00',
 '00',
 '00',
 '00',
 '00',
 '00']
  

Ответ №2:

Мои 2 цента: (?:^|s)([0-9a-fA-F]{2}(?:s|$))

https://regex101.com/r/I0gQlU/2

  • (?:^|s) : либо начало строки, либо пробел
  • [0-9a-fA-F]{2} : 2 шестнадцатеричных цифры
  • (?:s|$) : либо заканчивается пробелом, либо заканчивается строкой
  • : несколько раз (1 или более)

Ответ №3:

Вот как вы могли бы сделать это с помощью понимания списка, используя hexdigits из string библиотеки. Не уверен, как выполнить с помощью регулярного выражения:

 import string
s = 'ZZ 4B 0B 69 00 04 00 DD MN'
s = re.sub(r'ss.*', '', s)
' '.join([i for i in s.split(' ') if len(i) == 2 if i[0:1] in string.hexdigits])

'4B 0B 69 00 04 00 DD'
  

По сути, он перебирает строку, чтобы проверить, являются ли оба шестнадцатеричными.

Комментарии:

1. Спасибо за ответ, сложность заключается в том, что приведенное выше понимание списка не может обрабатывать такие случаи, 5 4B 0B 69 00 04 00 3 поскольку оно дает результат 5 4B 0B 69 00 04 00 3 , но желаемый 4B 0B 69 00 04 00

2. @CodingNow смотрите мой обновленный ответ с if len(i) == 2 Shoot, к сожалению, он также не сохранит 00 , поскольку это обманчиво. Я попытаюсь придумать более надежное решение.

3. вы не учитываете 1 или более пробелов, эта информация теряется из-за split()

4. это не улучшит ситуацию, потому что split() и split(' ') здесь одинаковы, ваш код завершится ошибкой во втором примере

5. s и s s являются «эквивалентными», второе s не имеет цели, лучше использовать s{2,} , или ss . это сбивает с толку то, что вы хотите