Корректное регулярное выражение для совпадения значений, сгенерированных uuid.uuid4().hex?
Вопрос: Как проверить, что значение соответствует UUID4, сгенерированному с помощью этого кода?
Я использую следующий код для генерации UUID4:
uuid.uuid4().hex
Убедитесь, что значение, которое я хочу проверить, является корректным UUID4. Является ли правильным решением использование регулярного выражения? Сгенерированные значения представляют собой 32-символьные строки в следующем формате:
60e3bcbff6c1464b8aed5be0fce86052
Как мне корректно выполнить валидацию этого значения в Python?
3 ответ(ов)
Как мне известно, ответ Мартина не является на 100% корректным. UUID версии 4 содержит пять групп шестнадцатеричных символов: первая группа состоит из 8 символов, вторая — из 4 символов, третья — из 4 символов, четвертая — из 4 символов и пятая — из 12 символов.
Однако для того, чтобы сделать его валидным UUID4, третья группа (которая находится посередине) должна начинаться с 4:
00000000-0000-4000-0000-000000000000
^
Кроме того, четвертая группа должна начинаться с 8, 9, a или b.
00000000-0000-4000-a000-000000000000
^ ^
Таким образом, вам необходимо изменить регулярное выражение Мартина на следующее:
import re
uuid4hex = re.compile('[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\Z', re.I)
Чтобы быть более конкретным. Вот самый точный регулярное выражение для захвата UUID версии 4 как с тире, так и без, которое соответствует всем правилам UUID4:
[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}
Вы можете убедиться, что оно также захватывает заглавные буквы, используя флаг игнорирования регистра. В моем примере используется re.I
. (UUID не содержат заглавных букв в своем выводе, но во входных данных это не вызывает ошибок, просто игнорируется. Это значит, что в UUID "f" и "F" считаются одинаковыми).
Я создал валидатор для их проверки, который выглядит следующим образом:
import re
def valid_uuid(uuid):
regex = re.compile('^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}\Z', re.I)
match = regex.match(uuid)
return bool(match)
Теперь вы можете сделать так:
if valid_uuid(my_uuid):
# Выполнить действия с валидным my_uuid
С помощью ^
в начале и \Z
в конце я также убеждаюсь, что в строке нет ничего лишнего. Это гарантирует, что "3fc3d0e9-1efb-4eef-ace6-d9d59b62fec5" вернёт True
, а "3fc3d0e9-1efb-4eef-ace6-d9d59b62fec5+19187" вернёт False
.
Обновление - приведенный способ на Python не является надежным - смотрите комментарии:
Существуют и другие способы валидации UUID. В Python можно сделать так:
from uuid import UUID
try:
UUID(my_uuid)
# my_uuid валидный, и вы можете его использовать
except ValueError:
# выполняйте нужные действия, когда my_uuid не является UUID
В качестве полезной заметки по вопросам производительности, я протестировал оба метода в терминах времени выполнения, и метод валидации с использованием регулярных выражений оказался немного быстрее:
import re
from uuid import UUID
def _validate_uuid4(uuid_string):
try:
UUID(uuid_string, version=4)
except ValueError:
return False
return True
def _validate_uuid4_re(uuid_string):
uuid4hex = re.compile('^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}\Z', re.I)
match = uuid4hex.match(uuid_string)
return bool(match)
Выполнив команды в ipython
, я получил следующие результаты:
> In [58]: val = str(uuid.uuid4())
> In [59]: %time _validate_uuid4(val)
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 30.3 µs
Out[59]: True
> In [60]: %time _validate_uuid4_re(val)
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 25.3 µs
Out[60]: True
> In [61]: val = "invalid_uuid"
> In [62]: %time _validate_uuid4(val)
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 29.3 µs
Out[62]: False
> In [63]: %time _validate_uuid4_re(val)
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 25.5 µs
Out[63]: False
Как видно из результатов, метод с регулярными выражениями (_validate_uuid4_re
) демонстрирует улучшенную производительность по сравнению с традиционным методом валидации UUID (_validate_uuid4
). Это особенно заметно при проверке неверного UUID: время выполнения оба метода примерно одинаково, но метод с регулярными выражениями все же оказывается чуть быстрее.
Фильтрация DataFrame pandas по критериям подстроки
Стоит ли использовать re.compile в Python?
Как сопоставить любой символ на нескольких строках в регулярном выражении?
Разделить строку по запятым, игнорируя запятые внутри двойных кавычек?
"Как использовать регулярное выражение Python с "\1" для обращения к захваченным группам?"