Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Remove comma(s) from String

940 views
Skip to first unread message

Martin Kelly

unread,
Apr 21, 1999, 3:00:00 AM4/21/99
to

Is there a more efficient way of removing the comma characters from a
string?

function RemoveCommas(aStr: String): String;
begin
// Remove Comma(s) from String
// e.g. 1,000,000.00 will now read 1000000.00
while Pos(',', aStr) > 0 do
Delete(aStr, Pos(',', AStr), 1);
Result := aStr;
end;

I could only come up with the above.

Just curious.

Martin Kelly


Roman Krejci

unread,
Apr 21, 1999, 3:00:00 AM4/21/99
to
Hi Martin,

function RemoveCommas(const aStr: String): String;
var cnt,len: integer;
pch,pchr: pChar;
begin
len := length(aStr);
SetLength(Result,len);
if len = 0 then exit;
Cnt := 0;
pCh := @aStr[1];
pChr := @Result[1];
For i := 1 to len do begin
if pCh^ <> ',' then begin
pChr^ := pCh^;
inc(Cnt);
inc(pChr);
end;
inc(pCh);
end;
SetLength(Result,Cnt);
end

is definitely more effective.

--
Roman
(please remove 'stopspam' in header when replying)
mail: in...@rksolution.cz
URL: www.rksolution.cz

Martin Kelly píše ve zprávě <7fkdd2$4d...@forums.borland.com>.

Earl F. Glynn

unread,
Apr 21, 1999, 3:00:00 AM4/21/99
to
Martin Kelly <mke...@pdqtechnology.co.uk> wrote in message news:7fkdd2$4d...@forums.borland.com...

> Is there a more efficient way of removing the comma characters from a
> string?

In D4 you could use the new StringReplace function:

type
TReplaceFlags = set of (rfReplaceAll, rfIgnoreCase);

function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;

efg
_________________________________
efg's Computer Lab: www.efg2.com/lab
Delphi Books: www.efg2.com/lab/TechBooks/Delphi.htm

Earl F. Glynn E-Mail: Earl...@att.net
Overland Park, KS USA


Philippe Ranger

unread,
Apr 21, 1999, 3:00:00 AM4/21/99
to
<<Martin:

Is there a more efficient way of removing the comma characters from a
string?

function RemoveCommas(aStr: String): String;


begin
// Remove Comma(s) from String
// e.g. 1,000,000.00 will now read 1000000.00
while Pos(',', aStr) > 0 do
Delete(aStr, Pos(',', AStr), 1);
Result := aStr;
end;
>>

You're right about the inefficiency. The true answer is to go get the free
HyperString from http://efd.home.mindspring.com/tools.htm (source is $39).
Otherwise, I'd like to correct Roman's blind infatuation with pointers, and
so slow too<g> --

Function stripChar (s: string; c: char): string;
(*Returns s minus all occurrences of c*)
Var
js: integer; //current index into s
js0: integer; //index of first uncopied char in s
jr: integer; //first unused position in result
Begin
setLength(result, length(s));
js0 := 1;
jr := 1;
for js := 1 to length(s) do if (s[js] = c) then begin
move(s[js0], result[jr], js-js0);
inc(jr, js-js0);
js0 := js + 1;
end;
move(s[js0], result[jr], length(s) + 1 - js0);
setLength(result, jr + length(s) - js0);
End;

PhR

Roman Krejci

unread,
Apr 22, 1999, 3:00:00 AM4/22/99
to
Thanks for correcting the "blind infantuation".
However, I must agree that your solution is better.
--
Roman


Martin Kelly

unread,
Apr 22, 1999, 3:00:00 AM4/22/99
to
Interesting. I like my 2-liner from the point of view of brevity. And
brevity is best - right Phil?

I'll try your code.

Thanks.

> You're right about the inefficiency. The true answer is to go get the free
> HyperString from http://efd.home.mindspring.com/tools.htm (source is
$39).
> Otherwise, I'd like to correct Roman's blind infatuation with pointers,
and
> so slow too<g> --
>
> Function stripChar (s: string; c: char): string;
> (*Returns s minus all occurrences of c*)
> Var

> js: integer; file://current index into s
> js0: integer; file://index of first uncopied char in s
> jr: integer; file://first unused position in result

Philippe Ranger

unread,
Apr 22, 1999, 3:00:00 AM4/22/99
to
<<Martin:

Interesting. I like my 2-liner from the point of view of brevity. And
brevity is best - right Phil?
>>

Better than that. Don't tell Roman, but for shortish strings with one or two
commas, I think your thing is faster. But HyperString is best.

PhR

Volker W. Walter

unread,
Apr 23, 1999, 3:00:00 AM4/23/99
to

Martin Kelly wrote:
>
> Is there a more efficient way of removing the comma characters from a
> string?
>
> function RemoveCommas(aStr: String): String;
> begin
> // Remove Comma(s) from String
> // e.g. 1,000,000.00 will now read 1000000.00
> while Pos(',', aStr) > 0 do
> Delete(aStr, Pos(',', AStr), 1);
> Result := aStr;
> end;
>

> I could only come up with the above.
>
> Just curious.
>
> Martin Kelly

I dont like to call Pos() twice per loop: perhaps someone likes this

function RemoveCommas(aStr: String): String;
VAR
p:integer;
BEGIN
p:=Pos(',',aStr);
WHILE (0<p) DO BEGIN
Delete(aStr,p,1);
p:=Pos(',',aStr);
END;
Result := aStr;
END;


pgr...@dynasty.net

unread,
Apr 25, 1999, 3:00:00 AM4/25/99
to
I was interested in how the various routines would stack up, so I ran
them all with two types of input: a short string, 29 bytes long with 4
commas (test looped 100000 times), and a long string, 60k long with
4890 commas. The tested versions, from longest to shortest were:

Glynn - Uses builtin "StringReplace"
Ranger - Indexed copy of characters between strings
Kelly - used "Pos" and "Delete"
Walter - Same as Kelly,except used only one "Pos"
HyperString - not actually posted - code follows
Krejci - used pchar copy routine

Timings in seconds were as follows:

Krejci .31 .006
Hyper .54 .008
Walter 1.08 5.98
Kelly 1.31 10.19
Ranger 6.10 33.12
Glynn 6.12 33.28

It appears that the original answer is by far the quickest, if not
necessarily the "best code". It certainly depends on how much it is
used which one you might want in your code. StringReplace is
certainly the cleanest but could take minutes instead of fractions of
a second for a large file.

The Hyperstring routine performed almost as well as the best, and
certainly is cleaner, if not exactly intuitive

function RemoveCommas_Hyper(const aStr:String):String;
begin
Result:=aStr;
SetLength(Result,DeleteC(Result,','));
end;

I have just downloaded Hyperstring, so have no experience with it.
Perhaps there is an even better way to do this.

Phil


Philippe Ranger

unread,
Apr 25, 1999, 3:00:00 AM4/25/99
to
<<Phil:

Glynn - Uses builtin "StringReplace"
Ranger - Indexed copy of characters between strings
Kelly - used "Pos" and "Delete"
Walter - Same as Kelly,except used only one "Pos"
HyperString - not actually posted - code follows
Krejci - used pchar copy routine

Timings in seconds were as follows:

Krejci .31 .006
Hyper .54 .008
Walter 1.08 5.98
Kelly 1.31 10.19
Ranger 6.10 33.12
Glynn 6.12 33.28
>>

Phil, thanks for the work and report.

I'm saddened to see that Roman's pointer-infatuated solution was faster than
mine. But I'm rather struck with disbelief to find pos+delete also several
times faster than mine. There's something wrong. If you used the right code
(stripChar), the only thing I can see is that Roman refers constantly to the
result string, and that this may produce much healthier cache management.

<<
function RemoveCommas_Hyper(const aStr:String):String;
begin
Result:=aStr;
SetLength(Result,DeleteC(Result,','));
end;
>>

Could be simplified to --

function RemoveCommas_Hyper(const aStr:String):String;
begin
Result:=aStr;

DeleteC(Result,','));
end;

PhR

Ernie Deel

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
Philippe Ranger <.> wrote in message news:7g0gc7$f3...@forums.borland.com...

> function RemoveCommas_Hyper(const aStr:String):String;
> begin
> Result:=aStr;
> SetLength(Result,DeleteC(Result,','));
> end;
> >>
>
> Could be simplified to --
>
> function RemoveCommas_Hyper(const aStr:String):String;
> begin
> Result:=aStr;
> DeleteC(Result,','));
> end;
>

Not quite. DeleteC only does a "pseudo-delete". In other words, it provides
the appearance of a deletion by shifting characters and space filling at the end
of string. If absolutely necessary, the fill spaces at the end can be manually
removed using SetLength() as in the first example above. Depending on the
application, this may not be necessary. For example, if the string is only
going to be used for display, a few extra spaces at the end may not make any
difference and the overhead of string re-allocation can be avoided.

For better performance, eliminate the overhead of the special function and code
it directly in-line. For example, instead of:

X := RemoveCommas_Hyper(Y);

use this:

X := Y;
SetLength(X,DeleteC(X,',')); //remove commas

--
Ernie Deel, EFD Systems
-------------------------------------------------
The future is just like the past, only more expensive.


Philippe Ranger

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
<<Ernie:

Not quite. DeleteC only does a "pseudo-delete". In other words, it
provides
the appearance of a deletion by shifting characters and space filling at the
end
of string. If absolutely necessary, the fill spaces at the end can be
manually
removed using SetLength() as in the first example above.
>>

Phil obviously read the docs better than I did -- he got to the Note which
is the main text! Imho, Ernie, this is carrying the need for speed a bit
far -- "delete" is already a standard procedure, and it does mean "remove
and shorten". I think the case where your result can be used as-is is the
exception, not the rule.

<<
SetLength(X,DeleteC(X,',')); //remove commas
>>

That's an argument. But you know how popular this C-type coding is with
Delphi users.

PhR

Ernie Deel

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
Philippe Ranger <.> wrote in message news:7g1ouj$gh...@forums.borland.com...

> Imho, Ernie, this is carrying the need for speed a bit
> far -- "delete" is already a standard procedure, and it does mean "remove
> and shorten".

Point taken.

This is admittedly somewhat controversial. Some users like it, others don't.
Now that it's done, it can't be undone without breaking existing code.

Philippe Ranger

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
<<Ernie:

This is admittedly somewhat controversial. Some users like it, others
don't.
Now that it's done, it can't be undone without breaking existing code.
>>

No. It's a naming problem, and done is done.

PhR

pgr...@dynasty.net

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
"Philippe Ranger" <.> wrote:

|I'm saddened to see that Roman's pointer-infatuated solution was faster than
|mine. But I'm rather struck with disbelief to find pos+delete also several
|times faster than mine. There's something wrong. If you used the right code

Something wrong indeed! I called Glynn's code twice - Copy and paste
bug. Sorry about that. I should have noticed the little blue dots
missing from your routine. I made one minor change to your code - the
"," was hard-coded, rather than passed, to make all functions the
same.

The corrected timings follow:

Timings in seconds were as follows:

Krejci .31 .006
Hyper .54 .008

Ranger .86 .010


Walter 1.08 5.98
Kelly 1.31 10.19

Glynn 6.12 33.28

Phil

Philippe Ranger

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
<<Phil:

Krejci .31 .006
Hyper .54 .008
Ranger .86 .010
>>

Thanks for the fix, but all I want is to beat Roman! Seriously, it still is
odd that HyperString, in asm, should be slower than Roman's code. It's as if
doing batch moves was slower than moving chars one at a time.

If you have the patience, try the following. It's my solution, but using
pointers like Roman does --


Function stripComma (s: string): string;
(*Returns s minus all occurrences of commas*)
Var
ps: pChar; //current char in s
ps0: pChar; //first uncopied char in s
pr: pChar; //first unused position in result
n: integer;
Begin
setLength(result, length(s));
ps := pChar(s);
ps0 := ps;
pr := pChar(result);
for n := 1 to length(s) do begin
if (ps^ = ',') then begin
move(ps0^, pr^, ps-ps0);
inc(pr, ps-ps0);
ps0 := ps + 1;
end;
inc(ps);
end;
move(ps0^, pr^, ps - ps0);
setLength(result, pr - pChar(result) + ps - ps0);
End;

PhR

Philippe Ranger

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
<<Wasis:
If the digit grouping symbol (Regional Settings) is '.' (dot), it works.
But if it is ',' (comma), it raises an exception. So I'd like to ask you
if there is another way to remove dot (or comma ->depends on the digit
grouping symbol)?
>>

The code I posted will strip any one char from a string. If you used
directly, I don't think you'd have a problem. The "digit grouping symbol" is
defined in SysUtils as "thousandSeparator", and initialized from local
settings. So, things should work if you simply did --

strToInt(stripChar(str, thousandSeparator));

I think your exception is raised because you've hard-coded the dot in, so
strToInt gets a string with commas left in it, and raises the exception.

PhR

Ernie Deel

unread,
Apr 26, 1999, 3:00:00 AM4/26/99
to
Philippe Ranger <.> wrote in message news:7g31n9$hk...@forums.borland.com...
> <<Phil:

> Seriously, it still is odd that HyperString, in asm, should be slower than
Roman's
> code.

The additional overhead of the special function call is the most likely cause.
Roman's routine is being called direct whereas the HyperString routines are not.
Each
additional level of indirection adds overhead.

Wasis Sugiono

unread,
Apr 27, 1999, 3:00:00 AM4/27/99
to
I have an application which performs like windows explorer.

This function is used to show the file size (with comma or dot) into
listview after retrieving using TSearchRec.

Function CommaStr(N : LongInt) : String;
Var
S : String;
R : Single;
Begin
R := N;
FmtStr(S, '%.0n', [r]);
Result := S;
End;

I use your function to calculate the size of multiple files so that it
returns integer instead of string.

SetLength(Temp, Length(Str));
j := 1;
k := 1;
For i := 1 To Length(Str) Do
If Str[i] = '.' Then
Begin
Move(Str[j], Temp[k], i - j);
Inc(k, i - j);
j := i + 1;
End;
Move(Str[j], Temp[k], Length(Str) + 1 - j);
SetLength(Temp, k + Length(Str) - j);
Result := StrToInt(Temp)

If the digit grouping symbol (Regional Settings) is '.' (dot), it works.
But if it is ',' (comma), it raises an exception. So I'd like to ask you
if there is another way to remove dot (or comma ->depends on the digit
grouping symbol)?

Is it possible using FmtStr?

Thanks in advance.

Regards,
Wasis

Philippe Ranger wrote:

> Function stripChar (s: string; c: char): string;
> (*Returns s minus all occurrences of c*)
> Var
> js: integer; //current index into s
> js0: integer; //index of first uncopied char in s
> jr: integer; //first unused position in result


> Begin
> setLength(result, length(s));
> js0 := 1;
> jr := 1;
> for js := 1 to length(s) do if (s[js] = c) then begin
> move(s[js0], result[jr], js-js0);
> inc(jr, js-js0);
> js0 := js + 1;
> end;
> move(s[js0], result[jr], length(s) + 1 - js0);
> setLength(result, jr + length(s) - js0);
> End;
>

> PhR

pgr...@dynasty.net

unread,
Apr 27, 1999, 3:00:00 AM4/27/99
to
"Philippe Ranger" <.> wrote:

|<<Phil:
|Krejci .31 .006
|Hyper .54 .008
|Ranger .86 .010
|>>

|Thanks for the fix, but all I want is to beat Roman! Seriously, it still is
|odd that HyperString, in asm, should be slower than Roman's code. It's as if
|doing batch moves was slower than moving chars one at a time.

|If you have the patience, try the following. It's my solution, but using
|pointers like Roman does --

Ranger2 .45 .005

Second-fastest for short string, fastest (slightly) for long string.
We're at the point where code placement could be the deciding factor.
A function that just copies input to output times:

null .05 .004

function RemoveCommas_Null(const aStr: String): String;
begin
Result:=aStr;
end;


Phil

Philippe Ranger

unread,
Apr 27, 1999, 3:00:00 AM4/27/99
to
<<Phil:
Ranger2 .45 .005

Second-fastest for short string, fastest (slightly) for long string.
We're at the point where code placement could be the deciding factor.
A function that just copies input to output times:
>>

You're a pearl, Phil. What do we do to keep you around?

This shows that Roman was dead right that pointer access is likely to be
faster. Drat it! Indexed access is both simpler and clearer.

It also shows that using Move only saves rather than wastes time when the
block approaches 14 bytes. A randomized comma placement would give more
accurate figures, but anyhow... I still figure Roman's code (which is
clearly simpler) wins out from better cache (or register?) optimization.

PhR


0 new messages