How to trim any character (or a substring) from a string?
Asked Answered
H

6

7

I use C# basically. There I can do:

string trimmed = str.Trim('\t');

to trim tabulation from the string str and return the result to trimmed.

In delphi7 I found only Trim, that trims spaces.

How can I achieve the same functionality?

Hellenic answered 21/11, 2012 at 4:39 Comment(1)
Do you really mean you want to trim a "substring" from the ends of a string? That's not what System.String.Trim does in .Net. That function accepts an array of characters, and then it trims all of them from either end of the current string. The order of the characters in the array is irrelevant.Pazpaza
W
7

This is a kind of procedure sometimes easier to create than to find where it lives :)

function TrimChar(const Str: string; Ch: Char): string;
var
  S, E: integer;
begin
  S:=1;
  while (S <= Length(Str)) and (Str[S]=Ch) do Inc(S);
  E:=Length(Str);
  while (E >= 1) and (Str[E]=Ch) do Dec(E);
  SetString(Result, PChar(@Str[S]), E - S + 1);
end;
Weller answered 21/11, 2012 at 5:11 Comment(3)
I was trying to do smth similar to your code. But you did it better.Hellenic
Rather than SetString with awkward PChar casting, you could call Copy.Pazpaza
@RobKennedy, agree, Copy looks nicer, it's interesting that in sources they use different assembly chains, possibly ending with slightly different performance consequences.Weller
D
12

There is string helper TStringHelper.Trim that accepts array of Char as optional parameter.

function Trim(const TrimChars: array of Char): string; overload;

So, you can use

trimmed := str.Trim([#09]);

for your example. #09 here is ASCII code for Tab character.

This function exists since at least Delphi XE3.

Hope it helps.

Domella answered 5/11, 2014 at 11:29 Comment(2)
Actually it's delphi 7 in question tagsHellenic
@Hellenic Oh, sorry. But author of question may take source of this function and rewrite it for Delphi 7.Domella
W
7

This is a kind of procedure sometimes easier to create than to find where it lives :)

function TrimChar(const Str: string; Ch: Char): string;
var
  S, E: integer;
begin
  S:=1;
  while (S <= Length(Str)) and (Str[S]=Ch) do Inc(S);
  E:=Length(Str);
  while (E >= 1) and (Str[E]=Ch) do Dec(E);
  SetString(Result, PChar(@Str[S]), E - S + 1);
end;
Weller answered 21/11, 2012 at 5:11 Comment(3)
I was trying to do smth similar to your code. But you did it better.Hellenic
Rather than SetString with awkward PChar casting, you could call Copy.Pazpaza
@RobKennedy, agree, Copy looks nicer, it's interesting that in sources they use different assembly chains, possibly ending with slightly different performance consequences.Weller
C
3

In Delphi the Trim function does not take parameters but it does trim other characters as well as spaces. Here's the code (from System.SysUtils in XE2, I don't think it has changed):

function Trim(const S: string): string;
var
  I, L: Integer;
begin
  L := Length(S);
  I := 1;
  if (L > 0) and (S[I] > ' ') and (S[L] > ' ') then Exit(S);
  while (I <= L) and (S[I] <= ' ') do Inc(I);
  if I > L then Exit('');
  while S[L] <= ' ' do Dec(L);
  Result := Copy(S, I, L - I + 1);
end;

It is trimming anything less than ' ' which would eliminate any control characters like tab, carriage return and line feed.

Countersignature answered 21/11, 2012 at 5:20 Comment(2)
@Konstantin - Tab is white spacePinon
@KonstantinVasilcov The code has definitely not changed since D7: code.google.com/p/sx-library/source/browse/trunk/ExtLib/Delphi7/…Countersignature
P
3

Delphi doesn't provide a function that does what you want. The built-in Trim function always trims the same set of characters (whitespace and control characters) from both ends of the input string. Several answers here show the basic technique for trimming arbitrary characters. As you can see, it doesn't have to be complicated. Here's my version:

function Trim(const s: string; c: Char): string;
var
  First, Last: Integer;
begin
  First := 1;
  Last := Length(s);
  while (First <= Last) and (s[First] = c) do
    Inc(First);
  while (First < Last) and (s[Last] = c) do
    Dec(last);
  Result := Copy(s, First, Last - First + 1);
end;

To adapt that for trimming multiple characters, all you have to do is change the second conditional term in each loop. What you change it to depends on how you choose to represent the multiple characters. C# uses an array. You could also put all the characters in a string, or you could use Delphi's native set type.

function Trim(const s: string; const c: array of Char): string;
// Replace `s[x] = c` with `CharInArray(s[x], c)`.

function Trim(const s: string; const c: string): string;
// Replace `s[x] = c` with `CharInString(s[x], s)`.

function Trim(const s: string; const c: TSysCharSet): string;
// Replace `s[x] = c` with `s[x] in c`.

The CharInArray and CharInString functions are easy to write:

function CharInArray(c: Char; ar: array of Char): Boolean;
var
  i: Integer;
begin
  Result := True;
  for i := Low(ar) to High(ar) do
    if ar[i] = c then
      exit;
  Result := False;
end;
// CharInString is identical, except for the type of `ar`.

Recall that as of Delphi 2009, Char is an alias for WideChar, meaning it's too big to fit in a set, so you wouldn't be able to use the set version unless you were guaranteed the input would always fit in an AnsiChar. Furthermore, the s[x] in c syntax generates warnings on WideChar arguments, so you'd want to use CharInSet(s[x], c) instead. (Unlike CharInArray and CharInString, the RTL provides CharInSet already, for Delphi versions that need it.)

Pazpaza answered 21/11, 2012 at 14:38 Comment(0)
B
1

You can use StringReplace:

var
  str:String;
begin
  str:='The_aLiEn'+Chr(VK_TAB)+'Delphi';

  ShowMessage(str);

  str:=StringReplace(str, chr(VK_Tab), '', [rfReplaceAll]);

  ShowMessage(str);
end;

This omits all Tab characters from given string. But you can improve it, if you want leading and trailing tabs to be removed then you can use Pos function also.

Edit: For the comment asking how to do it with Pos, here it is:

var
  str:String;
  s, e: PChar;
begin
  str:=Chr(VK_TAB)+Chr(VK_TAB)+'The_aLiEn'+Chr(VK_TAB)+'Delphi'+Chr(VK_TAB)+Chr(VK_TAB);

  s:=PChar(str);

  while Pos(Chr(VK_TAB), s)=1 do inc(s);
  e:=s;
  inc(e, length(s)-1);
  while Pos(Chr(VK_TAB), e)=1 do dec(e);
  str:=Copy(s, 1, length(s)-length(e)+1);

  ShowMessage(str);
end;

It is of course the same approach by Maksee's and a bit more job to do as it is. But if there isn't much time to finish the work and if Pos is what you've thought first, then this is how it can be done. You, the programmer should and have to think about optimizations, not me. And if we're talking constraints of optimization, with a little tweak to replace Pos with char compare, this will run faster than Maksee's code.

Edit for Substr search generalization:

function TrimStr(const Source, SubStr: String): String;
var
  s, e: PChar;
  l: Integer;
begin
  s:=PChar(Source);
  l:=Length(SubStr);

  while Pos(SubStr, s)=1 do inc(s, l);
  e:=s;
  inc(e, length(s)-l);
  while Pos(SubStr, e)=1 do dec(e, l);
  Result:=Copy(s, 1, length(s)-length(e)+l);
end;
Bhayani answered 21/11, 2012 at 4:56 Comment(5)
Did you read my question? I need to trim the string, but not replace all the tabs in itHellenic
For this answer to be any good at all, you'd need to at least demonstrate or describe how you think the Pos function would work for this task. Otherwise, I feel like you haven't understood the question at all.Pazpaza
@RobKennedy I've added a demonstration.Bhayani
And for the record, he is asking for "SubString" also.. How do you search a substring within a string?Bhayani
Quick note: VK_xxx are virtual keycodes, not character codes. Although they might match value-wise and they may never change, the reader should be aware that code like this builds on implicit premises (which is usually a bad thing). #9 would be the more idiomatic choice and still provide the same performance as it is translated at compile time.Daffi
B
0

The JEDI JCL v2.7 provides these useful functions for what you need:

function StrTrimCharLeft(const S: string; C: Char): string; function StrTrimCharsLeft(const S: string; const Chars: TCharValidator): string; overload; function StrTrimCharsLeft(const S: string; const Chars: array of Char): string; overload; function StrTrimCharRight(const S: string; C: Char): string; function StrTrimCharsRight(const S: string; const Chars: TCharValidator): string; overload; function StrTrimCharsRight(const S: string; const Chars: array of Char): string; overload; function StrTrimQuotes(const S: string): string;

Burris answered 18/3, 2016 at 11:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.