正则表达式,用于确认字符串是否是Python中的有效标识符

use*_*194 14 python regex for-loop identifier

我对标识符有以下定义:

Identifier --> letter{ letter| digit}
Run Code Online (Sandbox Code Playgroud)

基本上我有一个标识符函数,它从文件中获取一个字符串并对其进行测试,以确保它是上面定义的有效标识符.

我试过这个:

if re.match('\w+(\w\d)?', i):     
  return True
else:
  return False
Run Code Online (Sandbox Code Playgroud)

但是当我每次遇到一个整数运行我的程序时,它认为它是一个有效的标识符.

例如

c = 0 ;
Run Code Online (Sandbox Code Playgroud)

它打印c为有效的标识符,很好,但它也打印0为有效的标识符.

我在这做错了什么?

Mes*_*ion 22

官方参考:identifier ::= (letter|"_") (letter | digit | "_")*

所以正则表达式是:

^[^\d\W]\w*\Z
Run Code Online (Sandbox Code Playgroud)

示例(对于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)))
Run Code Online (Sandbox Code Playgroud)

结果:

'a' = True
'a1'    = True
'_a1'   = True
'1a'    = False
'aa$%@%'    = False
'aa bb' = False
'aa_bb' = True
'aa\n'  = False
Run Code Online (Sandbox Code Playgroud)

  • 我可能值得一提的是,这匹配了诸如"True","return"等关键字.我并不是建议对正则表达式进行更改,而只是OP可能想要记住这一点. (6认同)
  • @JoeCondron这也很容易做到,因为Python包含`keyword.iskeyword`函数,它只是关键字列表frozenset的包装器. (2认同)
  • 至少在 Python 3.6 中,这不适用于 Unicode 字符串 `'℘᧚'`,即使 ** 是 Python 3 中的有效标识符(并且不是关键字)。 (2认同)

Hat*_*sut 5

str.isidentifier()作品。正则表达式答案错误地匹配了一些有效的python标识符,而错误地匹配了一些无效的python标识符。

str.isidentifier() 如果根据语言定义,标识符和关键字部分,字符串是有效标识符,则返回true。

使用keyword.iskeyword()测试为保留的标识符,如高清和类。

@martineau的评论给出'??'了正则表达式解决方案失败之处的示例。

>>> '??'.isidentifier()
True
>>> import re
>>> bool(re.search(r'^[^\d\W]\w*\Z', '??'))
False
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

让我们定义与给定的正则表达式匹配的代码点集合,以及与匹配的集合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()}
Run Code Online (Sandbox Code Playgroud)

有多少个正则表达式匹配不是标识符?

In [26]: len(chars - identifiers)                                                                                                               
Out[26]: 698
Run Code Online (Sandbox Code Playgroud)

正则表达式不匹配多少个标识符?

In [27]: len(identifiers - chars)                                                                                                               
Out[27]: 4
Run Code Online (Sandbox Code Playgroud)

有趣-哪个?

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'),
])
Run Code Online (Sandbox Code Playgroud)

这两套有什么不同?

它们具有不同的Unicode“常规类别”值。

In [31]: {unicodedata.category(c) for c in chars - identifiers}                                                                                 
Out[31]: set(['Lm', 'Lo', 'No'])
Run Code Online (Sandbox Code Playgroud)

维基百科来看,那就是Letter, modifierLetter, other; Number, other。这与re docs一致,因为\d只有十进制数字:

\d 匹配任何Unicode十进制数字(即Unicode字符类别[Nd]中的任何字符)

那其他方式呢?

In [32]: {unicodedata.category(c) for c in identifiers - chars}                                                                                 
Out[32]: set(['Mn', 'Sm', 'So'])
Run Code Online (Sandbox Code Playgroud)

那是Mark, nonspacing; Symbol, math; Symbol, other

这些全部记录在哪里?

在哪里实施?

https://github.com/python/cpython/commit/47383403a0a11259acb640406a8efc38981d2255

我仍然想要一个正则表达式

查看PyPI 上的regex模块。

此正则表达式实现与标准“ re”模块向后兼容,但提供了其他功能。

它包括“常规类别”的过滤器。


Joe*_*Joe 2

\w 匹配数字和字符。尝试^[_a-zA-Z]\w*$

  • 请注意,Python 3 允许在其标识符中使用所有 Unicode 字母和数字。 (5认同)