我有一个包含字母、数字和其他字符的字符串。
我想从该字符串中删除所有数字、点和逗号
之前:'
Axis moving to new position - X-Pos: 5.4mm / Y-Pos: 3.5mm
'Axis moving to new position - X-Pos mm / Y-Pos mm
'不幸的是 string.replace() 只能替换一个字符。所以我需要几行。
如何避免逐行写入替换内容?
sString := sString.Replace('0', '');
sString := sString.Replace('1', '');
sString := sString.Replace('2', '');
sString := sString.Replace('3', '');
sString := sString.Replace('3', '');
...
sString := sString.Replace(':', '');
sString := sString.Replace('.', '');
虽然OP自己的解决方案很好,但是效率有点低。
为了完整起见,这里有一个稍微优化的版本:
function RemoveCharsFromString(const AString, AChars: string): string;
begin
SetLength(Result, AString.Length);
var ActualLength := 0;
for var i := 1 to AString.Length do
begin
if SomePredicate(AString[i]) then
begin
Inc(ActualLength);
Result[ActualLength] := AString[i];
end;
end;
SetLength(Result, ActualLength);
end;
该算法独立于特定谓词。在这种情况下,谓词是
Pos(AString[i], AChars) = 0
。
有多种方法可以解决这个问题。这是三个解决方案。
解决方案1
您可以简单地循环遍历源字符串,检查每个字符以查看它是否是需要删除的字符之一。
//Simple function that loops through all characters of the source strings removing them one by one
//It is manipulating the same string all the time
function Removechars1(sourceString: string; sCharsToBeRemoved: string):string;
var I: Integer;
begin
//Assign value of the source string to the result so we can work with result strin from now on
result := SourceString;
//Loop throught the whole result sring starting at end searching for characters to be removed
//We start at the end because when we will be removing characters from the string its length
//will be decreasing.
for I := Length(result) downto 1 do
begin
//Use Pos function to see if specific character in the result string can also be found
//in the sCharsToBeRemoved and therefore needs to be removed
if Pos(result[i], sCharsToBeRemoved) <> 0 then
begin
//If so we delete the specific character
Delete(result,I,1);
end;
end;
end;
解决方案2
第二个解决方案与第一个解决方案类似,但它依赖于向结果添加不可删除的字符。比第一个解决方案稍微慢一些
//Slightly faster function that also loops through the whole sourceString character by character
//and adds such characters to result string if they are not present in sCharsToBeRemoved string
function RemoveChars2(sourceString: string; sCharsToBeRemoved: string):string;
var I: Integer;
begin
//Prepare enpty string for our result strung to which we will be copying our end characters
result := '';
//Loop through the whole string
for I := 1 to Length(sourceString) do
begin
//If specific haracter can't be found in sCharsToBeRemoved copy that character to the
//result string
if Pos(sourceString[I], sCharsToBeRemoved) = 0 then
begin
result := result + sourceString[I];
end;
end;
end;
解决方案3
第三种解决方案依赖于字符串助手来替换特定字符。这是迄今为止三个解决方案中最快的,处理相同作业所需的时间大约是第一个解决方案的一半
//Another approach of removing characters from source string that relies on Replace string helper
function RemoveChars3(sourceString: string; sCharsToBeRemoved: string):string;
var I: Integer;
begin
//Assign value of the source string to the result so we can work with result strin from now on
result := sourceString;
//Loop through the sCharsToBeRemoved string so we can then call Replace string helper in order
//to replace all occurrences of such character in sourceString;
for I := 1 to Length(sCharsToBeRemoved) do
begin
result := result.Replace(sCharsToBeRemoved[I],'');
end;
end;
这种方法的主要优点是它非常快,并且可以轻松修改以能够删除整个子字符串而不仅仅是单个字符。
PS:在我的测试中,您的解决方案实际上是最慢的,比我的第一个解决方案多需要大约 20% 的时间
TestTring
jfkldajflkajdflkajlkčfjaskljflakjflkdasjflkčjdfkldafjadklfjadklfjaldkakljfkldajflkčadjslfkjadklfjlkadčjflkajdflčkjadlkfjladkdjfkladjflkadjflkčjadklčfjaldkjfkladjfklajflkadjfkadgfkljdklfjawdkojfkladsjflčaksdjdfklčasjdklčfdfklčjadslkdfjlka
CharsToBeRemoved
asjk
Solution 1
1230 ms
Solution 2
1263 ms
Solution 3
534 ms
Your solution
1574 ms
此解决方案适用于非常小的代码行占用空间。
我只是在每次出现应该删除的字符时分割字符串。之后,我将这些碎片放在一起,没有删除的字符。
用途:
sString := RemoveCharsFromString(sString, '1234567890.,');
uses System.SysUtils;
function RemoveCharsFromString(sFullString: string; sCharsToBeRemoved: string): string;
var
splitted: TArray<String>;
begin
splitted := sFullString.Split(sCharsToBeRemoved.ToCharArray());
Result := string.Join('', splitted);
end;
string.Replace 有一个重载,您可以传递标志来替换所有而不是仅一个。示例:
sString := sString.Replace('1', '', [rfReplaceAll, rfIgnoreCase]);
编辑:字符串列表等效项:
sString.Text := sString.Text.Replace('1', '', [rfReplaceAll, rfIgnoreCase]);
使用字符串会花费更多时间,请使用 PChar 代替。 我认为这是一个稍微优化的版本
function RemoveCharsFromString(const AString, AChars: String): String;
var
i, j, k, LenString, LenChars : Integer;
PString, PChars : PChar;
label
Ends;
begin
PString := Pointer(AString);
PChars := Pointer(AChars);
LenString := AString.Length;
LenChars := AChars.Length;
k := 0;
for i := 0 to LenString - 1 do
begin
for j := 0 to LenChars - 1 do
if PString[i] = PChars[j] then
Goto Ends;
PString[k] := PString[i];
Inc(k);
Ends :
end;
PString[k] := #0;
Result := StrPas(PString);
end;
如果您不喜欢标签,请使用此代码:
function RemoveCharsFromString(const AString, AChars: String): String;
var
i, j, k, LenString, LenChars : Integer;
PString, PChars : PChar;
found : Boolean;
begin
PString := Pointer(AString);
PChars := Pointer(AChars);
LenString := AString.Length;
LenChars := AChars.Length;
k := 0;
for i := 0 to LenString - 1 do
begin
found := False;
for j := 0 to LenChars - 1 do
if PString[i] = PChars[j] then
begin
found := True;
Break;
end;
if not found then
begin
PString[k] := PString[i];
Inc(k);
end;
end;
PString[k] := #0;
Result := StrPas(PString);
end;
你可以这样称呼它:
sString := RemoveCharsFromString(sString, '0123456789.,');