Регулярное выражение для подтверждения того, является ли строка допустимым идентификатором в Python
У меня есть следующее определение для идентификатора:
Identifier --> letter{ letter| digit}
В принципе у меня есть функция идентификатора, которая получает строку из файла и проверяет ее, чтобы убедиться, что она является допустимым идентификатором, как определено выше.
Я пробовал это:
if re.match('\w+(\w\d)?', i):
return True
else:
return False
но когда я запускаю свою программу каждый раз, когда она встречает целое число, она думает, что это действительный идентификатор.
Например
c = 0 ;
он печатает c
как допустимый идентификатор, который является точным, но также печатает 0
как допустимый идентификатор.
Что я здесь делаю неправильно?
Ответы
Ответ 1
Из официальной ссылки: identifier ::= (letter|"_") (letter | digit | "_")*
Итак, регулярное выражение:
^[^\d\W]\w*\Z
Пример (для Python 2 просто опустите re.UNICODE
):
import re
identifier = re.compile(r"^[^\d\W]\w*\Z", re.UNICODE)
tests = [ "a", "a1", "_a1", "1a", "aa$%@%", "aa bb", "aa_bb", "aa\n" ]
for test in tests:
result = re.match(identifier, test)
print("%r\t= %s" % (test, (result is not None)))
Результат:
'a' = True
'a1' = True
'_a1' = True
'1a' = False
'aa$%@%' = False
'aa bb' = False
'aa_bb' = True
'aa\n' = False
Ответ 2
Для Python 3 вам нужно обрабатывать буквы и цифры Unicode. Поэтому, если это вызывает беспокойство, вы должны ладить с этим:
re_ident = re.compile(r"^[^\d\W]\w*$", re.UNICODE)
[^\d\W]
соответствует символу, который не является цифрой, а не "не буквенно-цифровым", что означает "символ, который является буквой или подчеркиванием".
Ответ 3
str.isidentifier()
работает. Ответы регулярного выражения некорректно не совпадают с некоторыми действительными идентификаторами Python и неправильно совпадают с некоторыми недействительными.
str.isidentifier()
Возвращает true, если строка является допустимым идентификатором в соответствии с определением языка, разделом Идентификаторы и ключевыми словами.
Используйте keyword.iskeyword()
для проверки зарезервированных идентификаторов, таких как def и class.
Комментарий @martineau приводит пример '℘᧚'
когда решения регулярных выражений терпят неудачу.
>>> '℘᧚'.isidentifier()
True
>>> import re
>>> bool(re.search(r'^[^\d\W]\w*\Z', '℘᧚'))
False
Почему это происходит?
Позволяет определить наборы кодовых точек, которые соответствуют заданному регулярному выражению, и набор, который соответствует str.isidentifier
.
import re
import unicodedata
chars = {chr(i) for i in range(0x10ffff) if re.fullmatch(r'^[^\d\W]\w*\Z', chr(i))}
identifiers = {chr(i) for i in range(0x10ffff) if chr(i).isidentifier()}
Сколько совпадений регулярных выражений не являются идентификаторами?
In [26]: len(chars - identifiers)
Out[26]: 698
Сколько идентификаторов не совпадают с регулярными выражениями?
In [27]: len(identifiers - chars)
Out[27]: 4
Интересно - какие?
In [37]: {(c, unicodedata.name(c), unicodedata.category(c)) for c in identifiers - chars}
Out[37]:
set([
('\u1885', 'MONGOLIAN LETTER ALI GALI BALUDA', 'Mn'),
('\u1886', 'MONGOLIAN LETTER ALI GALI THREE BALUDA', 'Mn'),
('℘', 'SCRIPT CAPITAL P', 'Sm'),
('℮', 'ESTIMATED SYMBOL', 'So'),
])
Чем отличаются эти два набора?
Они имеют разные значения Unicode "General Category".
In [31]: {unicodedata.category(c) for c in chars - identifiers}
Out[31]: set(['Lm', 'Lo', 'No'])
Из Википедии это Letter, modifier
; Letter, other
; Number, other
. Это согласуется с документами, так как \d
это только десятичные цифры:
\d
Соответствует любой десятичной цифре Unicode (то есть любому символу в категории символов Unicode [Nd])
А как насчет другого пути?
In [32]: {unicodedata.category(c) for c in identifiers - chars}
Out[32]: set(['Mn', 'Sm', 'So'])
Это Mark, nonspacing
; Symbol, math
; Symbol, other
.
Где это все задокументировано?
Где это реализовано?
https://github.com/python/cpython/commit/47383403a0a11259acb640406a8efc38981d2255
Я все еще хочу регулярное выражение
Посмотрите на модуль регулярных выражений в PyPI.
Эта реализация регулярного выражения обратно совместима со стандартным модулем re, но предлагает дополнительные функциональные возможности.
Включает в себя фильтры для "общей категории".
Ответ 4
\ w соответствует цифрам и символам. Попробуйте ^[_a-zA-Z]\w*$
Ответ 5
Работает как шарм: r'[^\d\W][\w\d]+'