匹配数字和字符串的正则表达式

1 投票
6 回答
16277 浏览
提问于 2025-04-18 03:42

我有一系列的单词,如下所示:

476pe
e586
9999
rrr
ABCF

我需要写一个正则表达式,用来匹配数字和带字母的数字。从上面的字符串中,我只想匹配:

476pe
e586
9999

我尝试写了一个正则表达式,如下所示:

^[\D]*[0-9]+[\D]*$

但是它没有效果。我在一个在线正则表达式工具上试过,http://rubular.com/r/HQE2vG0pbu,结果显示整个字符串都在匹配。

6 个回答

1

最简单的这种表达式是

[0-9]

这个表达式会匹配每个包含至少一个数字的字符串。

1

试试这个:

(?im)^[a-z0-9]+$

示例:

if re.search("^[a-z0-9]+$", subject, re.IGNORECASE | re.MULTILINE):
    # Successful match
else:
    # Match attempt failed

演示:

http://regex101.com/r/oG2wP1

3

如果你只是想检查匹配,使用 \d 就够了。

或者可以用这个:

[^a-zA-Z\n]

这个会匹配前三个,但不会匹配那些只有字母的词。

这里有个演示:http://regex101.com/r/dO1tI1

5

因为其他回答已经提供了很多解决你问题的方法,我来试着解释一下你所观察到的行为。

首先,Rubular 是专门针对 Ruby 的正则表达式语法的。我不太清楚 Ruby 和 Python 的正则表达式引擎有什么具体不同。既然你提到了 ,你可能想使用 regex101debuggex。我会用这两个工具来解释。

现在,让我们看看你的正则表达式和数据,在这里。你的输入字符串是这样的:

476dn
e586
9999
rrr
ABCF

正则表达式可以以两种方式查看输入。可以把它看作是一个包含换行符的长字符串,或者是一个由换行符分隔的字符串列表。我们可以通过一个正则表达式标志来控制这种行为,这个标志叫做多行标志(在 Python 中是 re.MULTILINEre.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.findallre.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']
3

你这个正则表达式的问题在于,\D可以匹配任何不是数字的东西,所以它会错误地匹配那些在这个位置有特殊字符的字符串,并且无法匹配有多个数字组的字符串。

你可以试试像这样写:^[0-9a-zA-Z]*[0-9][0-9a-zA-Z]*$。这个表达式可以匹配任意数量的数字或字母,后面跟着一个数字,然后再跟任意数量的数字或字母。

这里有一个示例...

撰写回答