Delphi去除字符串中的符号

3

我已经搜索并尝试了几个循环,这些循环被认为可以从字符串中去除符号。我需要这个功能,因为某些位置会有“/”或其他类型的符号,我需要将其删除,因为FTP会认为它是一个文件夹,并且我需要用字符串作为名称。

字符串“place”根据人们的当前工作位置而异。例如,“place”=“S/A StorageRoom”,字符串的“/”部分让FTP认为它是一个子文件夹。

目前我正在使用这个功能,我认为它相当大,可以缩短:

   place := StringReplace(place, ',', '', [rfReplaceAll]);
   place := StringReplace(place, '.', '', [rfReplaceAll]);
   place := StringReplace(place, '/', '', [rfReplaceAll]);
   place := StringReplace(place, '!', '', [rfReplaceAll]);
   place := StringReplace(place, '@', '', [rfReplaceAll]);
   place := StringReplace(place, '#', '', [rfReplaceAll]);
   place := StringReplace(place, '$', '', [rfReplaceAll]);
   place := StringReplace(place, '%', '', [rfReplaceAll]);
   place := StringReplace(place, '^', '', [rfReplaceAll]);
   place := StringReplace(place, '&', '', [rfReplaceAll]);
   place := StringReplace(place, '*', '', [rfReplaceAll]);
   place := StringReplace(place, '''', '', [rfReplaceAll]);
   place := StringReplace(place, '"', '', [rfReplaceAll]);
   place := StringReplace(place, ';', '', [rfReplaceAll]);
   place := StringReplace(place, '_', '', [rfReplaceAll]);
   place := StringReplace(place, '(', '', [rfReplaceAll]);
   place := StringReplace(place, ')', '', [rfReplaceAll]);
   place := StringReplace(place, ':', '', [rfReplaceAll]);
   place := StringReplace(place, '|', '', [rfReplaceAll]);
   place := StringReplace(place, '[', '', [rfReplaceAll]);
   place := StringReplace(place, ']', '', [rfReplaceAll]);
   place := StringReplace(place, '\', '', [rfReplaceAll]);

编辑:

我目前正在使用 RAD Studio 10.1 Berlin


在文本中添加,目前我正在使用RAD Studio 10.1 Berlin。 - Relinkvent
我已经为您添加了标签。您能否编辑您的帖子,提供一个place中字符串样本?您可以使用正则表达式轻松完成此操作,但实际需要的特定表达式取决于您实际处理的文本,因此样本将非常有帮助。 - Ken White
可能是重复的问题:如何改进多个StringReplace调用? - GolezTrol
你对使用正则表达式有多熟悉?TRegEx.Replace 应该可以与 [\/,.!@#$%^&"';_():|[]]+ 一起使用。 - S. Langhammer
@S.Langhammer 我从未听说过 TRegEx.Replace,我会去查一下。 - Relinkvent
显示剩余2条评论
2个回答

6
为避免不必要的堆分配,这里提供一种变体方案以实现@Ancaron的答案,并仅进行一次分配和最终的长度调整来生成答案。
关键在于在开头预先分配结果字符串,然后用接受的字符填充它。在最后,调整结果字符串的长度即可。
program TestStripChars;

{$APPTYPE CONSOLE}

uses
  SysUtils;

function StripChars (const Text : string; const InValidChars : SysUtils.TSysCharSet) : string;
var
  i,j : Integer;
begin
  SetLength(Result,Length(Text));  // Preallocate result maximum length
  j := 0;  // Resulting string length counter
  for i := 1 to Length(Text) do begin
    if not CharInSet(Text[i],InValidChars) then begin
      Inc(j);
      Result[j] := Text[i];
    end;
  end;
  SetLength(Result,j); // Set result actual length
end;

var
  place : String;
begin
  place := 'Hell$$o D.,e.$lphi';
  place := StripChars(place,[',','.','$']);
  WriteLn(place);
  ReadLn;
end.

从评论中看来,OP正在使用零基字符串处理的编译器设置。

这里有一个函数可以处理两种情况:

function StripChars ( const Text : string; const InValidChars : SysUtils.TSysCharSet) : string;
var
  i,j,zbsAdj : Integer;
begin
  SetLength(Result,Length(Text));  // Preallocate result maximum length
  j := 0; // Resulting string length counter
  zbsAdj := 1-Low(String); // Handles zero based string offset
  for i := Low(Text) to High(Text) do begin
    if not CharInSet(Text[i],InValidChars) then begin
      Inc(j);
      Result[j-zbsAdj] := Text[i];
    end;
  end;
  SetLength(Result,j); // Set result actual length
end;

我在代码中遇到了一个奇怪的问题,基本上我将函数放入我的源代码中,使用名为'StripChars'的函数删除所有要删除的字符,我还使用了测试字符串“S/A StorageRoom”,发生的情况是一开始输出会像这样“ A StorageRoom”,有时会在“ S”的位置上出现奇怪的中文或其他字母,我想从0而不是1开始for循环,这解决了“SA StorageRoom”中“ S”的问题,但现在ftp会说无效字符并停止传输,有什么想法吗? - Relinkvent
忘了提到,奇怪的符号会发生在8/10次左右,其他时候它会工作,看起来像这样“漢S StorageRoom”或者在“漢”的位置上是其他东西。 - Relinkvent
1
看我的更新。你很可能正在使用一个带有 {$ZEROBASEDSTRINGS ON} 的编译器。我的编辑将为你处理这个问题。 - LU RD
顺便问一下,你的“减少分配”版本有多快?你有检查过吗? - Rudy Velthuis
1
@RudyVelthuis,32位编译器->快4-5倍,64位编译器快6-7倍。测试使用了OP的测试字符串。我知道Delphi的字符串在连接方面很快,这要归功于COW和FastMM内存管理器。但是,尽可能避免访问堆仍然是值得注意的。这在实际应用中真正值多少钱,取决于应用程序。 - LU RD
@LURD:好的,明白了。 - Rudy Velthuis

1
你只需要使用类似于以下的函数即可:


function StripChars ( const Text : string; InValidChars : TSetOfChar ) : string;
var
  S : string;
  i : integer;
begin
  Result := '';
  if Length(Text) > 0 then
  begin
    S := '';
    for i := 1 to length ( Text ) do
      if not CharInSet(Text[i],InValidChars) then  
        S := S + Text [ i ];
    Result := S;
  end;
end;

然后只调用


place := StripChars(place,[',','.', and so on]);

2
哎呀,这里有相当多的复制和重新分配。只需最多 2 次调用 SetLength 即可完成。 - David Heffernan
1
据我所知,内存管理器非常适应像重复使用 S := S + SomeChar 这样的场景。实际上并没有太多的重新分配,尽管人们可能会期望有更多。这就是为什么很少需要使用 StringBuilder 的原因。 - Rudy Velthuis

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