Проверка неверного идентификатора
Кажется, что все ответы в этой теме повторяют ошибку в валидации, которая позволяет сопоставлять строки, которые не являются допустимыми идентификаторами, такими же, как те.
Шаблоны регулярных выражений, предложенные в других ответах, построены из tokenize.Name
, который содержит следующий шаблон регулярных выражений [a-zA-Z_]\w*
(работает на python 2.7.15) и '$' привязку регулярных выражений.
Пожалуйста, обратитесь к официальному описанию Python 3 идентификаторов и ключевых слов (которое содержит абзац, который также относится к Python 2).
В пределах диапазона ASCII (U + 0001..U + 007F) допустимые символы для идентификаторов такие же, как в Python 2.x: прописные и строчные буквы от A до Z, подчеркивание _ и, за исключением первый символ, цифры от 0 до 9.
таким образом, 'foo \ n' не должен считаться действительным идентификатором.
Хотя можно утверждать, что этот код функционален:
>>> class Foo():
>>> pass
>>> f = Foo()
>>> setattr(f, 'foo\n', 'bar')
>>> dir(f)
['__doc__', '__module__', 'foo\n']
>>> print getattr(f, 'foo\n')
bar
Поскольку символ перевода строки действительно является допустимым символом ASCII, он не считается буквой. Более того, явно нет практического использования идентификатора, который заканчивается символом новой строки
>>> f.foo\n
SyntaxError: unexpected character after line continuation character
Функция str.isidentifier
также подтверждает, что это неверный идентификатор:
Python3 переводчик:
>>> print('foo\n'.isidentifier())
False
Якорь $
против якоря \Z
Цитирование официального синтаксиса регулярного выражения python2 :
$
Соответствует концу строки или непосредственно перед новой строкой в конце строки, а в режиме MULTILINE также соответствует перед новой строкой. foo совпадает как с «foo», так и с «foobar», а регулярное выражение foo $ соответствует только «foo». Что еще интереснее, поиск foo. $ В 'foo1 \ nfoo2 \ n' обычно соответствует 'foo2', но 'foo1' в режиме MULTILINE; при поиске одного $ в 'foo \ n' найдутся два (пустых) совпадения: одно непосредственно перед новой строкой, а другое в конце строки.
В результате получается строка, заканчивающаяся символом новой строки, который соответствует действительному идентификатору:
>>> import tokenize
>>> import re
>>> re.match(tokenize.Name + '$', 'foo\n')
<_sre.SRE_Match at 0x3eac8e0>
>>> print m.group()
'foo'
Шаблон регулярного выражения не должен использовать якорь $
, но вместо этого \Z
- это якорь, который следует использовать.
Цитирую еще раз:
\Z
Соответствует только в конце строки.
А теперь правильное регулярное выражение:
>>> re.match(tokenize.Name + r'\Z', 'foo\n') is None
True
Опасные последствия
См. Ответ Люка , где приведен еще один пример того, как такого рода слабое сопоставление регулярных выражений может потенциально в других обстоятельствах иметь более опасные последствия.
Дальнейшее чтение
В Python 3 добавлена поддержка не-ascii идентификаторов, см. PEP-3131 .