Michael Hutter
Michael Hutter

Reputation: 1532

Delphi: Remove chars from string

I have a string containing letters, numbers and other chars.
I want to remove from that string all numbers, dots and commas

Before: 'Axis moving to new position - X-Pos: 5.4mm / Y-Pos: 3.5mm'
After: 'Axis moving to new position - X-Pos mm / Y-Pos mm'

Unfortunately string.replace() only replaces one character. So I need several lines.

How can I avoid writing every replacement line by line?

  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('.', '');

Upvotes: 1

Views: 7138

Answers (5)

Michael Hutter
Michael Hutter

Reputation: 1532

This solution works with a very small footprint of code lines.
I just split the string on each occurence of a char which should be removed. After that I put the pieces together without the removed chars.

Usage:
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;

Upvotes: 1

AliReza
AliReza

Reputation: 184

Working with strings spends more time, use PChar instead. I think here's a slightly more optimized version

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;

If you don't like Labels, use this code :

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;

You can call it like this :

sString := RemoveCharsFromString(sString, '0123456789.,');

Upvotes: 0

Adriaan
Adriaan

Reputation: 806

string.Replace has an overload where you can pass flags to replace all instead of just one. Example:

sString := sString.Replace('1', '', [rfReplaceAll, rfIgnoreCase]);

Edit: Stringlist equivalent:

sString.Text := sString.Text.Replace('1', '', [rfReplaceAll, rfIgnoreCase]);

Upvotes: 0

SilverWarior
SilverWarior

Reputation: 8331

There are multiple ways of how you can approach this. Here are three solution.

Solution 1

You can go and simply loop though the source string checking each character to se if it is one of the characters that needs to be removed.

//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;

Solution 2

Second solution is similar to the first one but it relies on adding characters non removable characters to the result. It is slightly slower than the first solution

//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;

Solution 3

The third solution relies on string helpers for replacing specific characters. This one is by far the fastest of the three needing about half the time that is needed by the first solution to process the same job

//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;

Main advantages of this approach is that it is quite fast and could easily modified to be able to remove whole substrings and not only individual characters.

PS: In my testing your solution was actually the slowest needing about 20% more time than my first solution

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

Upvotes: 1

Andreas Rejbrand
Andreas Rejbrand

Reputation: 108948

Although the OP's own solution is fine, it is somewhat inefficient.

Just for completeness, here's a slightly more optimized version:

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;

The algorithm is independent of the particular predicate. In this case, the predicate is Pos(AString[i], AChars) = 0.

Upvotes: 3

Related Questions