You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi中移除字符串非数字字符的最优方案及内置函数查询

Delphi移除字符串中非数字字符的最佳实践

有没有内置函数?

Delphi的标准VCL/RTL库没有直接提供移除所有非数字字符的内置函数,你需要自己实现或者基于现有API封装。

现有三种实现的优缺点

1. 正向遍历拼接字符串

function RemoveNonNumericChars(const s: string): string;
begin
  Result := '';
  for var i := 1 to Length(s) do
  begin
    if s[i] in ['0'..'9'] then
      Result := Result + s[i];
  end;
end;
  • 优点:逻辑简单直观,易理解维护
  • 缺点:每次字符串拼接都会触发内存重新分配(Delphi字符串为不可变类型),长字符串场景下性能下降明显,还会产生内存碎片。

2. 反向遍历删除非数字字符

function RemoveNonNumericChars(const s: string): string;
begin
  Result := s;
  for var i := Length(Result) downto 1 do
  begin
    if not(Result[i] in ['0'..'9']) then
      Delete(Result, i, 1);
  end;
end;
  • 优点:基于输入副本修改,无需额外创建空字符串;反向遍历避免了删除字符后的索引偏移问题
  • 缺点:Delete操作会移动后续字符,非数字字符较多时,频繁的内存移动会拖慢速度,长字符串场景下性能一般。

3. 正则表达式替换

function RemoveNonNumericChars(const s: string): string;
begin
  var RegEx := TRegEx.Create('[^0-9]');
  Result := RegEx.Replace(s, '');
end;
  • 优点:代码最简洁,正则规则灵活(若后续需调整匹配逻辑,比如保留小数点、正负号,修改正则即可)
  • 缺点:性能最差——正则引擎初始化、模式编译、匹配遍历的开销远高于直接字符遍历,简单数字过滤场景属于过度设计。

更优的实现:预分配内存的正向遍历

针对第一个函数的性能短板,我们可以先统计数字字符数量,一次性分配足够内存,再填充字符,这是目前最快的实现方式:

function RemoveNonNumericChars(const s: string): string;
var
  i, Count: Integer;
begin
  Count := 0;
  // 先统计数字字符总数
  for i := 1 to Length(s) do
    if s[i] in ['0'..'9'] then
      Inc(Count);
  
  // 预分配目标字符串内存
  SetLength(Result, Count);
  Count := 0;
  // 填充数字字符
  for i := 1 to Length(s) do
    if s[i] in ['0'..'9'] then
    begin
      Inc(Count);
      Result[Count] := s[i];
    end;
end;

这个版本彻底避免了多次内存分配,所有操作都在预分配的内存中直接完成,处理长字符串时性能优势尤为显著。

如果使用Delphi 10.3+,还可以借助System.SpanUtils单元的Span进一步优化索引操作开销:

uses System.SpanUtils;

function RemoveNonNumericChars(const s: string): string;
var
  InputSpan: TSpan<char>;
  OutputSpan: TSpan<char>;
  OutputIdx: Integer;
begin
  InputSpan := s.AsSpan;
  OutputIdx := 0;
  // 统计数字数量
  for var C in InputSpan do
    if C in ['0'..'9'] then
      Inc(OutputIdx);
  
  SetLength(Result, OutputIdx);
  OutputSpan := Result.AsSpan;
  OutputIdx := 0;
  // 填充数字字符
  for var C in InputSpan do
    if C in ['0'..'9'] then
    begin
      OutputSpan[OutputIdx] := C;
      Inc(OutputIdx);
    end;
end;

最佳/最快方法总结

  • 最快性能:优先选择预分配内存的正向遍历实现,内存分配和字符操作开销最小,适配所有场景,尤其是长字符串处理。
  • 代码简洁性:若对性能要求不高(比如短字符串、低调用频率),正则表达式版本最省心。
  • 折中方案:反向删除版逻辑简单,性能略优于原始正向拼接,但仍不如预分配版本。

内容的提问来源于stack exchange,提问作者Shaun Roselt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 12:50:22