匹配数字和字符串的正则表达式
我有一系列的单词,如下所示:
476pe
e586
9999
rrr
ABCF
我需要写一个正则表达式,用来匹配数字和带字母的数字。从上面的字符串中,我只想匹配:
476pe
e586
9999
我尝试写了一个正则表达式,如下所示:
^[\D]*[0-9]+[\D]*$
但是它没有效果。我在一个在线正则表达式工具上试过,http://rubular.com/r/HQE2vG0pbu,结果显示整个字符串都在匹配。
6 个回答
最简单的这种表达式是
[0-9]
这个表达式会匹配每个包含至少一个数字的字符串。
试试这个:
(?im)^[a-z0-9]+$
示例:
if re.search("^[a-z0-9]+$", subject, re.IGNORECASE | re.MULTILINE):
# Successful match
else:
# Match attempt failed
演示:
如果你只是想检查匹配,使用 \d
就够了。
或者可以用这个:
[^a-zA-Z\n]
这个会匹配前三个,但不会匹配那些只有字母的词。
这里有个演示:http://regex101.com/r/dO1tI1
因为其他回答已经提供了很多解决你问题的方法,我来试着解释一下你所观察到的行为。
首先,Rubular 是专门针对 Ruby 的正则表达式语法的。我不太清楚 Ruby 和 Python 的正则表达式引擎有什么具体不同。既然你提到了 python,你可能想使用 regex101 或 debuggex。我会用这两个工具来解释。
现在,让我们看看你的正则表达式和数据,在这里。你的输入字符串是这样的:
476dn
e586
9999
rrr
ABCF
正则表达式可以以两种方式查看输入。可以把它看作是一个包含换行符的长字符串,或者是一个由换行符分隔的字符串列表。我们可以通过一个正则表达式标志来控制这种行为,这个标志叫做多行标志(在 Python 中是 re.MULTILINE
或 re.M
)。引用 Python 文档中的内容:
re.M
re.MULTILINE
当指定时,模式字符
'^'
匹配字符串的开头和每一行的开头(紧接在每个换行符后面);而模式字符'$'
匹配字符串的结尾和每一行的结尾(紧接在每个换行符前面)。默认情况下,'^'
只匹配字符串的开头,'$'
只匹配字符串的结尾和字符串结尾前的换行符(如果有的话)。
例如,在我们的例子中,如果这个标志没有启用,输入字符串将被视为一个包含换行符的长字符串,^
将匹配第一行中 4
前的位置,$
将匹配最后一行中 F
后的位置。
当这个标志启用时,^
和 $
将分别匹配第一个和最后一个字符前后的对应位置。所以,它们可以匹配以下情况:
- 当
^
是4
前的位置时,$
将是n
后的位置 - 当
^
是4
前的位置时,$
将是6
后的位置 - 当
^
是4
前的位置时,$
将是9
后的位置 - 当
^
是4
前的位置时,$
将是r
后的位置 - 当
^
是4
前的位置时,$
将是f
后的位置
- 当
^
是e
前的位置时,$
将是6
后的位置 - 当
^
是e
前的位置时,$
将是9
后的位置 - 当
^
是e
前的位置时,$
将是r
后的位置 - 当
^
是e
前的位置时,$
将是f
后的位置
- 当
^
是9
前的位置时,$
将是9
后的位置 - 当
^
是9
前的位置时,$
将是r
后的位置 - 当
^
是9
前的位置时,$
将是f
后的位置
- 当
^
是r
前的位置时,$
将是r
后的位置 - 当
^
是r
前的位置时,$
将是F
后的位置
- 当
^
是A
前的位置时,$
将是F
后的位置
由于它可以匹配多个位置,我们必须明确告诉正则表达式引擎,在使用多行字符串时,我们需要逐行匹配。在 Python 中,我们可以使用 re.findall
或 re.finditer
。在正则表达式的世界里,通常用标志 g
表示全局搜索。
有了这个基本理解后,让我们再看看你的数据。我相信 rubular 默认启用了这两个功能。我们可以清楚地看到匹配结果,带有捕获组,就像在这个 演示 中,使用的正则表达式是:
^([\D]*[0-9]+[\D]*)$
我们可以用 Python 找到匹配项,像这样:
regex = re.compile(r"^[\D]*[0-9]+[\D]*$", re.MULTILINE)
print regex.findall(data)
# ['476pe', 'e586', '9999\nrrr\nABCF']
给定的模式匹配第一行和第二行,这应该很简单。但第三个匹配一开始可能不太容易理解。当我们说 ^[\D]*
时,这意味着匹配 0 个或多个不是数字的字符。所以,空字符串也可以与 [\D]*
匹配。因此,在 9999
的开头,[\D]*
匹配 9999
前的空字符串,然后 [0-9]+
匹配数字 9999
,而字符串的其余部分直到结尾将由 [\D]*
匹配。它也匹配换行符,因为 \D
表示任何不是数字的字符。由于换行符不是数字,所以也会被匹配。
还要注意,\D
也允许其他特殊字符。引用文档中的内容:
当未指定
UNICODE
标志时,匹配任何非数字字符;这相当于集合[^0-9]
。如果有UNICODE
,它将匹配 Unicode 字符属性数据库中标记为数字的字符以外的任何字符。
所以,你可能想要更明确一些,就像在 tobias_k 的回答 中那样。
^[0-9a-zA-Z]*[0-9][0-9a-zA-Z]*$
这可以在 Python 中使用,像这样:
regex = re.compile(r"^[0-9a-zA-Z]*[0-9][0-9a-zA-Z]*$", re.MULTILINE)
print regex.findall(data)
# ['476pe', 'e586', '9999']
或者,如果你可以将字符串拆分成多个字符串,那么你可以这样做:
regex = re.compile(r"^[0-9a-zA-Z]*[0-9][0-9a-zA-Z]*$")
print [item for item in data.split() if regex.match(item)]
# ['476pe', 'e586', '9999']
你这个正则表达式的问题在于,\D
可以匹配任何不是数字的东西,所以它会错误地匹配那些在这个位置有特殊字符的字符串,并且无法匹配有多个数字组的字符串。
你可以试试像这样写:^[0-9a-zA-Z]*[0-9][0-9a-zA-Z]*$
。这个表达式可以匹配任意数量的数字或字母,后面跟着一个数字,然后再跟任意数量的数字或字母。
这里有一个示例...