如何在Python 2.6中获得isidentifier()功能?

16 投票
8 回答
2155 浏览
提问于 2025-04-15 21:02

Python 3 有一个字符串的方法,叫做 str.isidentifier

我想在 Python 2.6 中实现类似的功能,但不想自己重新写正则表达式之类的东西,应该怎么做呢?

8 个回答

2
re.match(r'[a-z_]\w*$', s, re.I)

这样做应该没问题。根据我所知道的,似乎没有什么内置的方法可以直接使用。

3

无效标识符验证


这个讨论中的所有回答似乎都在重复一个错误,就是在验证时允许一些不合法的字符串被当作合法标识符。

其他回答中提到的正则表达式模式是基于 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锚点


引用官方的Python 2正则表达式语法

$

匹配字符串的结尾,或者在字符串结尾的换行符之前,在多行模式下也匹配换行符之前的内容。foo可以匹配‘foo’和‘foobar’,而正则表达式foo$只匹配‘foo’。更有趣的是,在'foo1\nfoo2\n'中搜索foo.$会正常匹配‘foo2’,但在多行模式下会匹配‘foo1’;在'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

危险的隐患


请参见Luke的回答,了解这种弱正则匹配在其他情况下可能带来的更危险的后果。

进一步阅读


Python 3增加了对非ASCII标识符的支持,详见PEP-3131

15

tokenize模块定义了一个叫做Name的正则表达式

import re, tokenize, keyword
re.match(tokenize.Name + '$', somestr) and not keyword.iskeyword(somestr)

撰写回答