在C#开发中,从混合格式的字符串里提取数字是很常见的需求,比如需要从"订单号12345金额678元"这样的字符串中得到12345和678两个数值,或者只提取连续的数字片段。不同的字符串格式对应不同的实现方案,下面介绍几种常用的实现方式。
方法一:使用正则表达式提取数字
正则表达式是处理字符串匹配的高效工具,适合提取格式不固定的字符串中的数字,支持提取所有连续的数字片段,也可以根据需求调整匹配规则。
首先需要引入正则表达式相关的命名空间:
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
class Program
{
static void Main()
{
string testStr = "订单号12345,商品数量6,总价899.5元,优惠后799元";
// 匹配所有连续的数字(包含小数点的数字)
string pattern = @"d+(.d+)?";
MatchCollection matches = Regex.Matches(testStr, pattern);
List<string> numberStrs = new List<string>();
foreach (Match match in matches)
{
numberStrs.Add(match.Value);
}
Console.WriteLine("提取到的数字字符串:");
foreach (var num in numberStrs)
{
Console.WriteLine(num);
}
// 如果需要转为数值类型
List<double> numbers = new List<double>();
foreach (var numStr in numberStrs)
{
if (double.TryParse(numStr, out double num))
{
numbers.Add(num);
}
}
Console.WriteLine("转换后的数值:");
foreach (var num in numbers)
{
Console.WriteLine(num);
}
}
}
上述代码中,d+(.d+)?这个正则规则可以匹配整数和小数,如果需要只匹配整数,可以把规则改成d+。正则方式的优点是代码简洁,适配多种字符串格式,缺点是如果字符串很长、匹配规则复杂的话,性能会略低于遍历字符的方式。
方法二:遍历字符判断提取数字
如果字符串格式比较简单,或者需要更灵活的控制提取逻辑,可以通过遍历字符串的每个字符,判断是否是数字,再拼接成完整的数字字符串。
示例代码如下:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
string testStr = "用户ID1001,积分2500,等级3";
List<string> numberStrs = new List<string>();
string currentNum = "";
// 遍历字符串每个字符
foreach (char c in testStr)
{
// 判断字符是否是数字
if (char.IsDigit(c))
{
currentNum += c;
}
else
{
// 当前字符不是数字,且之前拼接了数字,就把数字加入结果
if (currentNum.Length > 0)
{
numberStrs.Add(currentNum);
currentNum = "";
}
}
}
// 处理字符串末尾是数字的情况
if (currentNum.Length > 0)
{
numberStrs.Add(currentNum);
}
Console.WriteLine("提取到的数字字符串:");
foreach (var num in numberStrs)
{
Console.WriteLine(num);
}
}
}
如果需要同时支持提取小数,可以在判断时加上对小数点的处理,示例调整如下:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
string testStr = "长度12.5cm,宽度3.8cm,高度10cm";
List<string> numberStrs = new List<string>();
string currentNum = "";
bool hasDot = false; // 标记当前数字是否已经包含小数点
foreach (char c in testStr)
{
if (char.IsDigit(c))
{
currentNum += c;
}
else if (c == '.' && !hasDot && currentNum.Length > 0)
{
// 当前是小数点,且之前有数字,且还没有小数点,就加入当前数字
currentNum += c;
hasDot = true;
}
else
{
if (currentNum.Length > 0)
{
// 如果最后一个字符是小数点,去掉再添加
if (currentNum.EndsWith("."))
{
currentNum = currentNum.Substring(0, currentNum.Length - 1);
}
if (currentNum.Length > 0)
{
numberStrs.Add(currentNum);
}
currentNum = "";
hasDot = false;
}
}
}
// 处理末尾的数字
if (currentNum.Length > 0)
{
if (currentNum.EndsWith("."))
{
currentNum = currentNum.Substring(0, currentNum.Length - 1);
}
if (currentNum.Length > 0)
{
numberStrs.Add(currentNum);
}
}
Console.WriteLine("提取到的数字字符串:");
foreach (var num in numberStrs)
{
Console.WriteLine(num);
}
}
}
遍历字符的方式性能较好,适合处理长字符串,而且可以自定义提取规则,比如只提取固定长度的数字,或者跳过某些位置的数字。
方法三:使用字符串分割提取数字
如果字符串的格式固定,数字和其他内容之间有固定的分隔符,比如"123,456,789"这种用逗号分隔的格式,或者"abc123def456ghi"这种非数字字符作为分隔的情况,可以使用string.Split方法结合判断来提取。
示例代码如下:
using System;
using System.Linq;
class Program
{
static void Main()
{
string testStr = "abc123def456ghi789";
// 按非数字字符分割
string[] parts = testStr.Split(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' }, StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine("提取到的数字字符串:");
foreach (var part in parts)
{
Console.WriteLine(part);
}
}
}
这种方式只适合分隔符固定且明确的场景,如果字符串格式不固定,使用这种方式很容易出现提取错误的情况,通用性不如前两种方法。
不同方法的适用场景
可以根据实际需求选择合适的方法:
- 如果字符串格式复杂,需要快速实现提取逻辑,优先选择正则表达式方式,代码量少且适配性强。
- 如果需要处理很长的字符串,或者对性能要求较高,优先选择遍历字符判断的方式,执行效率更高。
- 如果字符串格式固定,分隔符明确,可以选择字符串分割的方式,逻辑更简单。
提取到数字字符串之后,通常需要转为对应的数值类型,比如int、double等,建议使用TryParse方法而不是直接Parse,避免字符串格式不符合数值要求时抛出异常,提高程序的稳定性。