从字符串中删除数字

10
我想知道如何从一个字符串中删除数字。我尝试使用StringReplace函数,但我不知道如何告诉函数我想替换数字。
这是我尝试的代码:
StringReplace(mString, [0..9], '', [rfReplaceAll, rfIgnoreCase]);

Delphi XE及以上版本支持正则表达式,可用于字符串替换。它在RegularExpressions和RegularExpressionsCore单元中。 - Hendra
6个回答

13

简单而有效。可以优化,但作为起点应该可以满足您的需求:

function RemoveNumbers(const aString: string): string;
var
  C: Char;
begin
  Result := '';
  for C in aString do begin
      if not CharInSet(C, ['0'..'9']) then
      begin
        Result := Result + C;
      end;
    end;
end;

虽然我非常喜欢使用正则表达式,但是在解决这个特定问题时,我同意Nick的解决方案更快。如果有任何更复杂的情况,我会毫不犹豫地使用正则表达式! - Cesar Marrero
你可以考虑使用 TStringBuilder 来避免在追加字符时进行不必要的内存重新分配:SB := TStringBuilder.Create(Length(aString));... SB.Append(C); ... Result := SB.ToString; SB.Free; 这类似于 Wouter 回答中的概念,只是使用了一个类包装器。 - Remy Lebeau

5

相当迅速的原地版本。

procedure RemoveDigits(var s: string);
var
  i, j: Integer;
  pc: PChar;
begin
  j := 0;
  pc := PChar(@s[1]);
  for i := 0 to Length(s) - 1 do
    if pc[i] in ['0'..'9'] then 
               //if CharInSet(pc[i], ['0'..'9']) for Unicode version
      Inc(j)
    else
      pc[i - j] := pc[i];
  SetLength(s, Length(s) - j);
end;

3
如果原始字符串较大,使用就地替换的方法会更加节约内存。任何类似于 str := str + ? 或其他生成临时字符串的方法都可能在简单的转换例程(例如十六进制到二进制、base64等)用于大数据集(几兆字节)时快速占用大量内存。+1 表示支持就地替换。 - Dampsquid

5
这个版本的输出与Nick的版本相同,但是对于短字符串来说,这个更快3倍以上。文本越长,差距越大。
function RemoveNumbers2(const aString: string): string;
var
  C:Char; Index:Integer;
begin
  Result := '';
  SetLength(Result, Length(aString));
  Index := 1;
  for C in aString do
    if not CharInSet(C, ['0' .. '9']) then
    begin
      Result[Index] := C;
      Inc(Index);
    end;
  SetLength(Result, Index-1);
end;

如果不必要,不要浪费宝贵的CPU周期。


1
使用此代码。
function RemoveNonAlpha(srcStr : string) : string;
const
CHARS = ['0'..'9'];
var i : integer;
begin
result:='';
for i:=0 to length(srcStr) do
if  (srcstr[i] in CHARS) then
result:=result+srcStr[i];
end   ;

你可以这样调用它。

edit2.text:=RemoveNonAlpha(edit1.text);


这个可行,但函数被倒置了: 它正在删除 alpha 字符 :p - delphirules

1

我厌倦了寻找已经构建好的函数,所以我创建了自己的函数:

   function RemoveNumbers(const AValue: string): string;
   var
      iCar : Integer;
      mBuffer : string;
   begin
      mBuffer := AValue;

      for iCar := Length(mBuffer) downto 1 do
      begin
         if (mBuffer[iCar] in ['0'..'9']) then
            Delete(mBuffer,iCar,1);
      end;
      Result := mBuffer;
   end;

4
你的函数会失败,因为for循环计数器被缓存了,并且你在循环中缩短了字符串。 - Sertac Akyuz
2
但是您可以通过反转删除的顺序(使用 for ... downto)来解决此问题。只需记住,string 中的字符从 1 开始索引,而不是从 0 开始。 - Andriy M
1
我更喜欢Nick的版本。他写的代码更干净易读,而且不太可能出错。而你的代码使用了更多的内存,可能会更慢。在一个病态情况下,如果我传入一个' a123908908203809.... '(一个2GB的字符串,只有第一个字符不是数字),他的代码仍然可以工作。很好。而你的呢?效果就不那么好了。在一个反向情况下,对于中等大小的字符串,只需要删除一个数字,你的代码可能会更快,内存使用差异可能并不重要,但它仍然不够易读。 - Warren P

-1

StringReplace不接受集合作为第二个参数。也许有更合适的方法,但这个方法可行:

StringReplace(mString, '0', '', [rfReplaceAll, rfIgnoreCase]);
StringReplace(mString, '1', '', [rfReplaceAll, rfIgnoreCase]);    
StringReplace(mString, '2', '', [rfReplaceAll, rfIgnoreCase]);

等等。


6
呸!你能说“DRY”(不要重复自己)吗?很抱歉,我必须将此投票为对所提出问题的可怕解决方案的反对票。 - Ken White
同意...你至少可以循环一下.. for i := 0 to 9 do StringReplace(mString, I, '', [rfReplaceAll, rfIgnoreCase]); - John Easley
嘿,肯恩,请对我温柔点! :-) “可怕?”是的,for循环有优势。但是,有时候增加复杂性会增加错误。约翰的代码(除非他在我发布这篇文章后进行了编辑)是一个很好的例子:首先,它无法编译。假设他打算让“i”成为整数,正确的代码有点棘手。第二个参数应该是chr(ord('0') + i),不是吗?或者for循环应该是for ch := chr('0') to chr('9')。两者都增加了一些复杂性,并没有直接回答他的问题,即如何使用StringReplace。我想原帖作者可以轻松地按照您的建议修改代码。 - RobertFrank
@RobertFrank,我们两个的代码片段都不会起作用,因为StringReplace是一个函数 :) 话虽如此,“可怕”这个词在这里有点过了... - John Easley

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