Python,正则表达式匹配数字,x,xxx,xxx但不是xx,xx,x,

时间:2016-03-06 04:18:18

标签: python regex

第一次发帖,我已经潜伏了一段时间,对这里乐于助人的社区感到非常兴奋。

所以,使用Al Sweigart的“自动化无聊的东西”

进行一项练习,要求我构建一个以标准数字格式查找数字的正则表达式。三位数,逗号,三位数字,逗号等......

所以希望能匹配1,234和23,322和1,234,567和12但不是1,23,1或者1111,或其他任何愚蠢的东西。

我有以下内容。

import re

testStr = '1,234,343'
matches = []
numComma = re.compile(r'^(\d{1,3})*(,\d{3})*$')

for group in numComma.findall(str(testStr)):
    Num = group
    print(str(Num) + '-')           #Printing here to test each loop
    matches.append(str(Num[0]))

#if len(matches) > 0:
#    print(''.join(matches))

哪个输出....

('1',',343') -

我不确定为什么中间的“,234”被跳过了。正如我所说,正则表达式有问题。似乎无法绕过这一个。

任何帮助或解释都将不胜感激。

跟随编辑。因此,在遵循了我可以吸收的所有建议之后,我得到了完美的工作以进行多次输入。

import re

testStr = '1,234,343'
numComma = re.compile(r'^(?:\d{1,3})(?:,\d{3})*$')

Num = numComma.findall(testStr)
print(Num)

给了我......

[ '1234343']

大!但!当我将字符串输入更改为

之类的时候怎么办?

'1,234,343和12,345'

相同的代码返回....

[]

Grrr ......哈哈,这很有趣,我必须承认。

因此,练习的目的是能够最终扫描一段文本并以此格式挑选出所有数字。任何见解?我以为这会添加一个额外的元组,而不是返回一个空元素......

关注编辑:

所以,一天之后(忙于3个女儿和亲爱的名单),我终于能够坐下来检查我收到的所有帮助。这就是我想出来的,它看起来完美无瑕。包括我个人理解的评论。再次感谢Blckknght,Saleem,mhawke和BHustus。

我的最终代码:

import re

testStr = '12,454 So hopefully will match 1,234 and 23,322 and 1,234,567 and 12 but not 1,23,1 or ,,1111, or anything else silly.'

numComma = re.compile(r'''
    (?:(?<=^)|(?<=\s))  # Looks behind the Match for start of line and whitespace
    ((?:\d{1,3})        # Matches on groups of 1-3 numbers.
    (?:,\d{3})*)        # Matches on groups of 3 numbers preceded by a comma
    (?=\s|$)''', re.VERBOSE)    # Looks ahead of match for end of line and whitespace

Num = numComma.findall(testStr)
print(Num)

返回:

['12,454','1,234','23,322','1,234,567','12']

再次感谢!我在这里有过如此积极的首发​​经历,太棒了。 =)

4 个答案:

答案 0 :(得分:4)

问题是由于您在模式中使用重复捕获组(,\d{3})*。 Python的正则表达式引擎将匹配您的数字的千位和一组,但只会捕获最后一次重复。

我怀疑你想要使用非捕获组。将?:添加到每组括号的开头(我还建议,在一般原则上,使用原始字符串,尽管您当前模式中没有转义问题):

numComma = re.compile(r'^(?:\d{1,3})(?:,\d{3})*$')

由于没有捕获任何组,re.findall将返回整个匹配的文本,我认为这是您想要的。您还可以使用re.findre.search并在返回的group()对象上调用match方法来获取整个匹配的文本。

答案 1 :(得分:1)

问题是:

正则表达式匹配将返回每个组的元组项。 但是,区分捕获非常重要。由于您只有两个以括号分隔的组,因此匹配将始终为两个元组:第一组和第二组。但第二组比赛两次。

1:第一组,被捕获 ,234:第二组,被捕获 ,343也是第二组,这意味着它会覆盖 ,234

不幸的是,似乎vanilla Python没有办法以类似于.NET的正则表达式实现的方式访问除最后一个组之外的任何组的捕获。 然而,如果您只想获取具体数字,最好的办法是使用re.search(number)。如果它返回非None值,则输入字符串是有效数字。否则,它不是。

另外:你的正则表达式A test。请注意,正如Paul Hankin所说,测试用例6和7虽然不应该匹配,但由于第一个捕获组之后的第一个*,这将使初始组匹配任意次。否则,你的正则表达式是正确的。 Fixed version.

编辑回应:
现在你的正则表达式返回一个空集的原因是&#39;和&#39;是因为正则表达式中的^和$锚点。在正则表达式开头的^锚点说,这一点需要在一个字符串的开头处。 $是它的对应物,说&#39;这需要在字符串的末尾&#39;。如果您希望整个字符串从头到尾与模式匹配,那么这很好,但是如果您想要挑选多个数字,则应该取消它们。

无论其!
如果将正则表达式保留为当前形式的sans anchors,它现在将1,23,45的各个元素作为单独的数字匹配。因此,为此,我们需要添加一个零宽度正向前瞻断言,然后说,确保在此数字后面是空格或行的末尾&#39;。您可以看到更改here。尾端(?=\s|$)是我们的前瞻性断言:它不会捕获任何内容,只是确保标准或满足,在这种情况下是空格(\s)或(| )一行的结尾($)。

但是:在类似的情况下,之前的正则表达式将在&#34; 1234,567&#34;中匹配2,向我们提供数字&#34; 234,567&#34;,这将是不好的。所以我们使用后面的断言,类似于我们最后的前瞻:(?<!^|\s),只在字符串的开头匹配,或者在数字前面有空格。这个版本可以找到here,并且应该完全满足任何与非十进制数相关的需求。

答案 2 :(得分:0)

尝试:

import re
p = re.compile(ur'(?:(?<=^)|(?<=\s))((?:\d{1,3})(?:,\d{3})*)(?=\s|$)', re.DOTALL)

test_str = """1,234 and 23,322 and 1,234,567 1,234,567,891 200 and 12 but
not 1,23,1 or ,,1111, or anything else silly"""

for m in re.findall(p, test_str):
    print m

它的输出将是

  • 1234
  • 23322
  • 1234567
  • 1234567891
  • 200
  • 12

您可以看到演示here

答案 3 :(得分:0)

此正则表达式将匹配任何有效数字,并且永远不会匹配无效数字:

  

(?<=^|\s)(?:(?:0|[1-9][0-9]{0,2}(?:,[0-9]{3})*))(?=\s|$)

https://regex101.com/r/dA4yB1/1