查找字符串中最后一次出现的数字,并按该值拆分字符串

Posted

技术标签:

【中文标题】查找字符串中最后一次出现的数字,并按该值拆分字符串【英文标题】:Find the last occurrence of a number in a string, and split the string by that value 【发布时间】:2021-12-02 03:03:31 【问题描述】:

我想要完成的是找到字符串中的最后一个数字并按该值分割。

string packageSize = "4/8.75LB";

上面我有一个字符串,我想将其拆分为一个字符串数组,并将它们放入数据库中的两个不同列中。第一部分是小数,最后一部分是字符串或 varchar。

我在下面有这段代码,它似乎正在工作。只是想知道是否有更好的解决方案,或者我错过了一个已回答的问题。

string value = Regex.Match(packageSize, @"(\d+)(?!.*\d)", RegexOptions.RightToLeft).ToString();
int lastIndex = packageSize.LastIndexOf(value) + value.Length;
string packageLoad = packageSize.Substring(0, lastIndex);
decimal loadDecimal = Convert.ToDecimal(packageLoad);

感谢您的帮助!

【问题讨论】:

【参考方案1】:

你可以使用

var output = Regex.Split(packageSize, @"(\d)(?=\D*$)");

(\d)(?=\D*$) 正则表达式匹配并捕获带有 (\d) 的数字,该数字也与 Regex.Split 返回(它输出捕获的子字符串)。 (?=\D*$) 确保 (\d) 匹配字符串中的最后一个数字。

见C# demo:

var packageSize = "4/8.75LB";
var result = Regex.Split(packageSize, @"(\d)(?=\D*$)");
foreach (var s in result)
    Console.WriteLine(s);

// => 4/8.7
//    5
//    LB

如果您需要确保正则表达式拆分确实发生,请检查输出数组的长度是否不等于1

var packageSize = "4/8.75LB";
//var packageSize = "LB"; // => 'LB' did not match the regex.
var result = Regex.Split(packageSize, @"(\d)(?=\D*$)");
if (result.GetLength(0) != 1)  // We have found a match
    foreach (var s in result)
        Console.WriteLine(s);

else

    Console.WriteLine($"'packageSize' did not match the regex.");

见this C# demo。

另外,如果只需要匹配 ASCII 数字,请使用Regex.Split(packageSize, @"(\d)(?=\D*$)", RegexOptions.ECMAScript)

【讨论】:

【参考方案2】:

您可以在匹配最后一个数字之前的第一部分和匹配最后一个数字之后的第二部分使用 2 个捕获组。

如果您希望每个组至少匹配一个字符,请将量词更改为 + 而不是 *

^(.*)[0-9](\D*)$
^ 字符串开始 (.*)捕获组1,匹配任意字符 [0-9] 匹配单个数字 0-9 (\D*)捕获组2,可选匹配非数字 $ 字符串结束

Regex demo

例如

string packageSize = "4/8.75LB";
Regex r = new Regex(@"^(.*?)[0-9](\D*)$");
foreach (Match m in r.Matches(packageSize))

    Console.WriteLine(m.Groups[1].Value);
    Console.WriteLine(m.Groups[2].Value);

输出

4/8.7
LB

【讨论】:

(.*)\d(\D*) 可以吗? @CaiusJard 你说的没错,内容多在最后,回溯会少。【参考方案3】:

“我想找到最后一位,并将字符串分成两边的两个”

在性能方面,我认为你不会比循环做得更好:

for(int i = str.Length-1; i>=0; i--)
  if(Char.IsDigit(str[i]))
    return (str[..i], str[(i+1)..]);
  

它返回一个("4/8.7", "LB")的元组

--

您可以将其调整为以下之一:

var i = str.LastIndexOfAny("0123456789".ToCharArray());

var i = Array.FindLastIndex(str.ToCharArray(), Char.IsDigit);

return (str[..i], str[(i+1)..]);

让我感到困惑的是,您在 cmets 中给出的规范与您在问题中给出的代码完全不同。您的代码“有效”,但4/8.7 不可能Convert.ToDecimal..

【讨论】:

【参考方案4】:

不是 100% 确定我是否正确理解了要求,但是此正则表达式将捕获第一组中输入字符串中的最后一个数字(无论是否为十进制)和第二组中的以下字符:

(\d+(?:\.\d+)?)(\D*)$

因此,输入字符串"4/8.75LB" 将被拆分为:

第 1 组:"8.75" 第 2 组:"LB"

【讨论】:

以上是关于查找字符串中最后一次出现的数字,并按该值拆分字符串的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL Regex 查找最后一个数字并拆分

在某个字符的最后一次出现处拆分字符串

如何使用正则表达式拆分字符串以返回值列表?

MYSQL:查找字符串中字符的最后一次出现

如何在PostgreSQL中的字符串中查找特定字符的第一次和最后一次出现

查找字符串中任意数字第一次出现的位置