第一次发帖,我已经潜伏了一段时间,对这里乐于助人的社区感到非常兴奋。
所以,使用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']
再次感谢!我在这里有过如此积极的首发经历,太棒了。 =)
答案 0 :(得分:4)
问题是由于您在模式中使用重复捕获组(,\d{3})*
。 Python的正则表达式引擎将匹配您的数字的千位和一组,但只会捕获最后一次重复。
我怀疑你想要使用非捕获组。将?:
添加到每组括号的开头(我还建议,在一般原则上,使用原始字符串,尽管您当前模式中没有转义问题):
numComma = re.compile(r'^(?:\d{1,3})(?:,\d{3})*$')
由于没有捕获任何组,re.findall
将返回整个匹配的文本,我认为这是您想要的。您还可以使用re.find
或re.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
它的输出将是
您可以看到演示here
答案 3 :(得分:0)
此正则表达式将匹配任何有效数字,并且永远不会匹配无效数字:
(?<=^|\s)(?:(?:0|[1-9][0-9]{0,2}(?:,[0-9]{3})*))(?=\s|$)