匹配字符串中最后一个数字的正则表达式

54

我需要提取一个字符串中的最后一个数字。我正在尝试使用正则表达式和负向先行断言来实现,但是它没有起作用。这是我拥有的正则表达式:

\d+(?!\d+)

以下是一些字符串,仅用于让您了解正则表达式应匹配的内容:

ARRAY[123]         matches 123 
ARRAY[123].ITEM[4] matches 4
B:1000             matches 1000
B:1000.10          matches 10

等等,此正则表达式匹配了所有数字,但我不明白为什么负向先行断言没有起作用。有人能解释一下吗?

4个回答

134

你的正则表达式\d+(?!\d+)表示

匹配任何数字,如果它不是紧接着跟随另一个数字。

这是不正确的。如果一个数字没有被任何其他数字(在任何位置上)跟随,那么它就是最后一个数字。

翻译成正则表达式为:

(\d+)(?!.*\d)

Rubular 链接


1
+1,这比我的 (?:\D|^) 混乱得多;-)(而且更接近 OP 的原始正则表达式)。 - Cameron
1
谢谢您的解释。我没有意识到需要包括“.*”才能不仅仅是立即匹配。 - korbes
这个问题让我苦恼了好久,感谢您提供了一个优雅的解决方案。 - Steven Garcia
喜欢这个解决方案,因为它是任何其他“字符串中最后x个字符”的需求的良好起点。格式为(regex)(?!.*(regex))。个人喜欢查找任何十进制数,所以我经常使用的正则表达式是:((?:\d*\.)?\d+)(?!.*((?:\d*\.)?\d+)) - TheUnknownGeek
很好!但是我该如何匹配一个从最后一个数字之后但在特定单词之前开始的表达式呢?f1rst number 77, 2 substring-that-I-need before KEYWORD 3 asd 555?我想要获取这部分内容:substring-that-I-need before - help-ukraine-now

11
你可以使用。
.*(?:\D|^)(\d+)
为了获得最后一个数字; 这是因为匹配器将使用.*吞掉所有字符,然后回溯到第一个非数字字符或字符串的开头,然后匹配最后一组数字。
你的负向先行断言不起作用,因为在例如字符串“1 3”上,1\d+匹配,然后空格与负向先行断言匹配(因为它不是一个或多个数字序列)。3甚至都没有被考虑过。
请注意,您的示例正则表达式中没有任何分组,因此我不确定您是如何提取数字的。

只是好奇,为什么你的正则表达式中有 (?:\D|^) 这一部分? .* 不是可以很好地处理它吗? - jb.
2
@jb:嘿,我一开始也是用的那个,但后来不得不删除我的答案,同时想出了 (?:\D|^).*(\d+) 的问题在于只有最后一个数字会被匹配(因为引擎一旦满足正则表达式就会停止,而在回溯一个数字字符后它就会满足)。 - Cameron
如果你像使用 .* 一样从字符串的开头进行锚定,那么你需要使用 (?:\D+^) 或等效的 [\D\A]。如果你从字符串的末尾进行锚定,则不需要它,就像 codaddict 或者我的答案一样。 - sawa
@sawa:哦,\A,我总是忘记这些锚点。不幸的是,当它与\D一起在字符类中时,我的Python 2.6会出错。 - Cameron

11

我的理解是:你需要确保匹配结果足够靠近字符串结尾;这里的“足够靠近”指只允许非数字字符出现在匹配结果后面。我建议采用以下方法:

/(\d+)\D*\z/
  1. \z 表示字符串的结尾。
  2. \D* 表示匹配和字符串的结尾之间可以有任意数量的非数字字符。
  3. (\d+) 是匹配部分,用括号包围起来是为了方便提取,正如Cameron所指出的那样。

1
我不知道\z,它似乎不起作用(JavaScript)。我使用$代替:/(\d+)\D*$/ - Yukulélé

0

我仍然在处理捕获组方面遇到了问题(例如,如果使用内联修饰符(?imsxXU))。

这对我的目的起作用-

.(?:\D|^)\d(\D)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接