正则表达式如何找到字符串中最后一个(右侧)数字组?

7
寻找一个正则表达式字符串,可以找到嵌入字符串中最右侧(如果有的话)的数字组。我们只关心连续的数字。我们不关心符号、逗号、小数点等。如果找到了这些,应该像字母一样被视为非数字。
这是为替换/增量目的而进行的,因此我们还需要获取检测到的数字之前和之后的所有内容,以便在增加值后重构字符串,所以我们需要一个标记化的正则表达式。
以下是我们要查找的示例:
- "abc123def456ghi" 应该识别出'456' - "abc123def456ghi789jkl" 应该识别出'789' - "abc123def" 应该识别出'123' - "123ghi" 应该识别出'123' - "abc123,456ghi" 应该识别出'456' - "abc-654def" 应该识别出'654' - "abcdef" 不应返回任何匹配项
例如,从名称“Item 4-1a”开始,提取出“1”,并将其前面的所有内容作为前缀,将其后面的所有内容作为后缀。然后,在代码循环中,我们可以使用它来生成值“Item 4-2a”、“Item 4-3a”和“Item 4-4a”。
现在,如果我要寻找第一组,这很容易。我只需要找到前缀中0个或多个非数字的第一个连续块,然后找到数字的1个或多个连续块,然后剩余的所有内容将成为后缀。
我遇到的问题是如何将前缀定义为包括除最后一组以外的所有(如果有的话)数字。无论我尝试什么样的前缀,它都会吞噬掉最后一组,即使我已经尝试通过基本上颠倒上述内容来将其锚定到结尾。

您可以使用@Birei提供的正则表达式进行分割,并在连接之前更新第二个索引以获得所需的结果。 - Devendra D. Chavan
怎么进行字符串分割?如果字符串是'a44b44c',前缀应该是'a44b'。如果我要进行太多的手动操作,那么这就打败了使用正则表达式的初衷,因为它已经支持命名捕获组。 - Mark A. Donohoe
1
我所说的“split”是指(Regex.Split),因此在先前的评论中有超链接。使用Regex.Split()将为a44b44c提供3个标记,即a44b44c - Devendra D. Chavan
啊!我不知道那个。它很好用! - Mark A. Donohoe
5个回答

15

如何考虑这个:

^(.*?)(\d+)(\D*)$
然后增加第二组并连接所有三组。
说明:
^         : Begining of string
  (       : start of 1st capture group
    .*?   : any number of any char not greedy
  )       : end group
  (       : start of 2nd capture group
    \d+   : one or more digits
  )       : end group
  (       : start of 3rd capture group
    \D*   : any number of non digit char
  )       : end group
$         : end of string

第一个捕获组将匹配到最后一组数字中最后一个数字之前的所有字符。

或者如果你可以使用命名捕获组

^(?<prefix>.*?)(?<number>\d+)(?<suffix>\D*)$

根据最后一组数字的位置不同,这可能比我的代码更有效。+1 - ridgerunner
好的,这个很好用...但我不知道它是怎么工作的!你能否编辑一下,以便显示每个操作的注释?例如,在你的第一个组中,我甚至被卡住了...(.*?)...因为我认为在句点后问号和星号是互斥的,但显然我是错的。 - Mark A. Donohoe
谢谢解释! :) 非贪婪模式正是我所需要的!你得到了我的投票!谢谢! :) - Mark A. Donohoe
从未见过这种使用 : comment 记录正则表达式的方法,好主意,谢谢。 - aliopi

7
尝试使用以下正则表达式:
(\d+)(?!.*\d)

解释:

(\d+)           # One or more digits.
(?!.*\d)        # (zero-width) Negative look-ahead: Don't find any characters followed with a digit.

编辑(问题的离题):这个答案是错误的,但这个问题已经在其他帖子中得到了回答,为了避免删除这个问题,我将以另一种方式使用这个相同的正则表达式,例如在Perl中可以像这样使用它来获得与C#相同的结果(增加最后一个数字):

s/(\d+)(?!.*\d)/$1 + 1/e;

不太对。虽然它正确地识别了数字,但仍然没有展示如何对字符串进行标记化以获取前缀和后缀,这正是我主要困扰的问题。你能帮忙吗? - Mark A. Donohoe
@MarqueIV:你说得对,不是你想要的,我误解了重点,抱歉。但现在有一些正确的答案可以很好地解决你的问题。 - Birei

3

您也可以尝试更简单的版本:

(\d+)[^\d]*$

1
这些其他的对我都不起作用...只有这个可以。简单就是一种药物。 - Alex Gray
这里有一个测试,确认它按预期工作:http://regex101.com/r/hN8zG5/1 - Leniel Maccaferri

1
这应该可以解决问题:
Regex regexObj = new Regex(@"
    # Grab last set of digits, prefix and suffix.
    ^               # Anchor to start of string.
    (.*)            # $1: Stuff before last set of digits.
    (?<!\d)         # Anchor start of last set of digits.
    (\d+)           # $2: Last set of one or more digits.
    (\D*)           # $3: Zero or more trailing non digits.
    $               # Anchor to end of string.
    ", RegexOptions.IgnorePatternWhitespace);

1

不使用正则表达式怎么样?这里有一段代码片段(适用于控制台)

string[] myStringArray = new string[] { "abc123def456ghi", "abc123def456ghi789jkl", "abc123def", "123ghi", "abcdef","abc-654def" };

        char[] numberSet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
        char[] filterSet = new char[] {'a','b','c','d','e','f','g','h','i','j','k','l','m',
                                        'n','o','p','q','r','s','t','u','v','w','x','y','z','-'};
        foreach (string myString in myStringArray)
        {
            Console.WriteLine("your string - {0}",myString);
            int index1 = myString.LastIndexOfAny(numberSet);
            if (index1 == -1)
            Console.WriteLine("no number");
            else
            {
               string mySubString = myString.Substring(0,index1 + 1);
               string prefix = myString.Substring(index1 + 1);
               Console.WriteLine("prefix - {0}", prefix);
               int index2 = mySubString.LastIndexOfAny(filterSet);
               string suffix = myString.Substring(0, index2 + 1);
               Console.WriteLine("suffix - {0}",suffix);
               mySubString = mySubString.Substring(index2 + 1);
               Console.WriteLine("number - {0}",mySubString);
               Console.WriteLine("_________________");
            }
        }
        Console.Read();

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