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

时间:2011-03-29 14:18:14

标签: python regex for-loop identifier

我对标识符有以下定义:

Identifier --> letter{ letter| digit}

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

我试过这个:

if re.match('\w+(\w\d)?', i):     
  return True
else:
  return False

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

例如

c = 0 ;

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

我在这里做错了什么?

6 个答案:

答案 0 :(得分:22)

来自official referenceidentifier ::= (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

答案 1 :(得分:3)

对于Python 3,您需要处理Unicode字母和数字。所以,如果这是一个问题,你应该相处:

re_ident = re.compile(r"^[^\d\W]\w*$", re.UNICODE)

[^\d\W]匹配不是数字而不是“非字母数字”的字符,该字符转换为“字母或下划线字符”。

答案 2 :(得分:3)

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

  

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

     

使用keyword.iskeyword()测试保留标识符,例如def   和课。

@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“常规类别”值。

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

wikipedia中为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'])

那是Mark, nonspacingSymbol, math; Symbol, other

这些全部记录在哪里?

在哪里实现?

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

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

查看PyPI上的regex模块。

  

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

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

答案 3 :(得分:2)

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

答案 4 :(得分:0)

像魅力一样运作:r'[^\d\W][\w\d]+'

答案 5 :(得分:0)

这个问题是关于正则表达式的,所以我的回答可能与主题不符。关键是正则表达式根本不是正确的方法。

有兴趣获取有问题的字符吗?

使用 str.isidentifier,您可以逐个字符地执行检查,在它们前面加上下划线,以避免误报,例如数字等......如果名称之一是有效的,那么名称如何有效(前缀)组件不是(?)例如

def checker(str_: str) -> 'set[str]':
    return {
        c for i, c in enumerate(str_)
        if not (f'_{c}' if i else c).isidentifier()
    }
>>> checker('℘3᧚₂')
{'₂'}

哪个解决方案处理未经授权的第一个字符,例如数字或例如。见

>>> checker('᧚℘3₂')
{'₂', '᧚'}
>>> checker('3᧚℘₂')
{'3', '₂'}
>>> checker("a$%@#%\n")
{'@', '#', '\n', '$', '%'}

有待改进,因为它既不检查保留名称,也不说明为什么 有时会出现问题,而 总是......但这是我的无正则表达式方法。


的话回答:

if not checker(i):
    return True
else:
    return False

哪些可以签约

return not checker(i)