3

什么是匹配字符串中任何有效的 Python 整数文字的正则表达式?它应该支持所有额外的东西,比如oand l,但不匹配浮点数或其中包含数字的变量。我正在使用 Python 的re,所以它支持的任何语法都可以。

编辑:这是我的动机(显然这很重要)。我正在尝试修复http://code.google.com/p/sympy/issues/detail?id=3182。我想要做的是为 IPython 创建一个钩子,它自动将 int/int (like 1/2) 转换为Rational(int, int), (like Rational(1, 2)。原因是否则不可能1/2注册为有理数,因为它是 Python 类型的__div__Python 类型。在SymPy,这可能很烦人,因为当你想要的是一个精确的数量 时,x**(1/2)会创建x**0(或x**0.5使用除法或 Python 3)之类的东西。__future__x**Rational(1, 2)

我的解决方案是在 IPython 中添加一个钩子,该钩子会自动将输入中的所有整数文字包装为 Integer(SymPy 的自定义整数类,Rational用于除法)。这将让我添加一个选项isympy,让 SymPy 在这方面更像一个传统的计算机代数系统,对于那些想要它的人来说。我希望这可以解释为什么我需要它来匹配任意 Python 表达式中的任何和所有文字,这就是为什么它不需要匹配名称中带有数字的浮点文字和变量。

另外,由于每个人都对我尝试的内容如此感兴趣,所以这里是:在我放弃之前没有多少(正则表达式很难)。我试着(?!\.)让它不捕捉浮点文字的第一部分,但这似乎不起作用(如果有人能告诉我为什么,我会很好奇,一个例子是re.sub(r"(\d*(?!\.))", r"S\(\1\)", "12.1"))。

编辑 2re.sub :由于我打算将它\1

4

6 回答 6

5

整数字面量的定义是(在 3.x 中,在 2.x 中略有不同):

integer        ::=  decimalinteger | octinteger | hexinteger | bininteger
decimalinteger ::=  nonzerodigit digit* | "0"+
nonzerodigit   ::=  "1"..."9"
digit          ::=  "0"..."9"
octinteger     ::=  "0" ("o" | "O") octdigit+
hexinteger     ::=  "0" ("x" | "X") hexdigit+
bininteger     ::=  "0" ("b" | "B") bindigit+
octdigit       ::=  "0"..."7"
hexdigit       ::=  digit | "a"..."f" | "A"..."F"
bindigit       ::=  "0" | "1"

所以,像这样:

[1-9]\d*|0|0[oO][0-7]+|0[xX][\da-fA-F]+|0[bB][01]+

基于说你想支持“l”,我猜你实际上想要2.x 定义

longinteger    ::=  integer ("l" | "L")
integer        ::=  decimalinteger | octinteger | hexinteger | bininteger
decimalinteger ::=  nonzerodigit digit* | "0"
octinteger     ::=  "0" ("o" | "O") octdigit+ | "0" octdigit+
hexinteger     ::=  "0" ("x" | "X") hexdigit+
bininteger     ::=  "0" ("b" | "B") bindigit+
nonzerodigit   ::=  "1"..."9"
octdigit       ::=  "0"..."7"
bindigit       ::=  "0" | "1"
hexdigit       ::=  digit | "a"..."f" | "A"..."F"

可以写成

(?:[1-9]\d+|0|0[oO]?[0-7]+|0[xX][\da-fA-F]+|0[bB][01]+)[lL]?
于 2012-07-31T04:55:14.887 回答
4

http://docs.python.org/reference/lexical_analysis.html#integers中描述了语法。这是将其表示为正则表达式的一种方法:

(0|[1-9][0-9]*|0[oO]?[0-7]+|0[xX][0-9a-fA-F]+|0[bB][01]+)[lL]?

免责声明:这不支持负整数,因为在 Python 中,-in 之类的东西-31实际上并不是整数文字的一部分,而是一个单独的运算符。

于 2012-07-31T04:53:42.230 回答
4

我不相信使用 re 是要走的路。Python 具有tokenize、和模块ast,可用于解析/处理/操作/重写 Python 代码...symbolparser

>>> s = "33.2 + 6 * 0xFF - 0744"
>>> from StringIO import StringIO
>>> import tokenize
>>> t = list(tokenize.generate_tokens(StringIO(s).readline))
>>> t
[(2, '33.2', (1, 0), (1, 4), '33.2 + 6 * 0xFF - 0744'), (51, '+', (1, 5), (1, 6), '33.2 + 6 * 0xFF - 0744'), (2, '6', (1, 7), (1, 8), '33.2 + 6 * 0xFF - 0744'), (51, '*', (1, 9), (1, 10), '33.2 + 6 * 0xFF - 0744'), (2, '0xFF', (1, 11), (1, 15), '33.2 + 6 * 0xFF - 0744'), (51, '-', (1, 16), (1, 17), '33.2 + 6 * 0xFF - 0744'), (2, '0744', (1, 18), (1, 22), '33.2 + 6 * 0xFF - 0744'), (0, '', (2, 0), (2, 0), '')]
>>> nums = [eval(i[1]) for i in t if i[0] == tokenize.NUMBER]
>>> nums
[33.2, 6, 255, 484]
>>> print map(type, nums)
[<type 'float'>, <type 'int'>, <type 'int'>, <type 'int'>]

在http://docs.python.org/library/tokenize.html有一个示例,它将浮点数重写为decimal.Decimal

于 2012-07-31T07:58:50.647 回答
2

如果你真的想匹配两种“方言”,你会得到一些歧义,例如八进制(oPython 3 中需要)。但以下应该有效:

r = r"""(?xi) # Verbose, case-insensitive regex
(?<!\.)       # Assert no dot before the number
\b            # Start of number
(?:           # Match one of the following:
 0x[0-9a-f]+| # Hexadecimal number
 0o?[0-7]+|   # Octal number
 0b[01]+|     # Binary number
 0+|          # Zero
 [1-9]\d*     # Other decimal number
)             # End of alternation
L?            # Optional Long integer
\b            # End of number
(?!\.)        # Assert no dot after the number"""
于 2012-07-31T06:19:04.737 回答
1

这样的事情就足够了吗?

r = r"""
(?<![\w.])               #Start of string or non-alpha non-decimal point
    0[X][0-9A-F]+L?|     #Hexadecimal
    0[O][0-7]+L?|        #Octal
    0[B][01]+L?|         #Binary
    [1-9]\d*L?           #Decimal/Long Decimal, will not match 0____
(?![\w.])                #End of string or non-alpha non-decimal point
"""

(带旗帜re.VERBOSE | re.IGNORECASE

于 2012-07-31T05:27:23.317 回答
0

这非常接近:

re.match('^(0[x|o|b])?\d+[L|l]?$', '0o123l')
于 2012-07-31T05:00:41.157 回答