[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2555
  • Last Modified:

Remove all space, line breaks and paragrahs from text

I have a bunch of text in a Tmemo component, could look like this (could be any text)

Hello my name is bob and
I have two cats, each can catch
four mice a day

Or whatever
What I need is to make it

Hello my name is bob and I have two cats, each can catch four mice a day

Even
HellomynameisbobandIhavetwocats,eachcancatchfourmiceaday

I have tired replacing all the ' ' with '' but no go, have tried using trim, again no go.
Basically, if I had a 20 line string in a Memo, I want it all on 1 line. Yes I have turned off word wrap.



0
wildzero
Asked:
wildzero
  • 6
  • 3
  • 3
  • +5
1 Solution
 
Wim ten BrinkCommented:
Memo.Lines.Text := StringReplace(Memo.Lines.Text, #13#10, '', [rfReplaceAll]);

Tried that already? :-)
0
 
esoftbgCommented:
procedure TForm1.Button1Click(Sender: TObject);
var
  I:      Integer;
  P:      Integer;
  S:      string;
  T:      string;
begin
  T := '';
  Memo2.Clear;
  for I := 0 to Memo1.Lines.Count-1 do
  begin
    S := Memo1.Lines[I];
//    StringReplace(S, ' ', '', [rfReplaceAll]);
    P := Pos(' ', S);
    while (P>0) do
    begin
      Delete(S, P, 1);
      P := Pos(' ', S);
    end;
    T := T + S;
  end;
  Memo2.Text := T;
end;
0
 
Wim ten BrinkCommented:
To remove space, use:
 Memo.Lines.Text := StringReplace(Memo.Lines.Text, ' ', '', [rfReplaceAll]);

To remove all cats, use:
 Memo.Lines.Text := StringReplace(Memo.Lines.Text, 'cat', '', [rfReplaceAll, rfIgnoreCase]);

You get the picture?
#13#10 stands for Carriage-return plus Linefeed. Basically, that's what separates lines in a stringlist.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
wildzeroAuthor Commented:
Yea I get that ;)
What am getting is with the memo1, if I have 5 pages of text it reduces it to 6-7 lines
WIth a richedit I get it down to 3 lines

So I guess it's a limit with the components, if I load it into a string list ,or maybe just assign it to a stringvar do you think it'd keep 1 line?
0
 
Amir AzhdariCommented:
try to use stringvar as esoftbg wrote and also you  can try this :

procedure TForm1.Button1Click(Sender: TObject);
var delimitedtext:String;i,j:integer;
    delimitedtextremoveallspaces:string;
begin
memo1.Lines.Delimiter:=' ';
memo1.Lines.QuoteChar:='~';
setlength(delimitedtext,length(memo1.text));
setlength(delimitedtextremoveallspaces,length(memo1.text));


delimitedtext:=memo1.lines.DelimitedText;
  while Pos('~', delimitedtext) > 0 do
    delimitedtext[Pos('~', delimitedtext)] := ' ';
// delimitedtext is now delimited text without removing spaces


// delimitedtextremoveallspaces is now delimited text with removing spaces
j:=1;
for i:=1 to length(delimitedtext) do
 if delimitedtext[i]<>' ' then
  begin
   delimitedtextremoveallspaces[j]:=delimitedtext[i];
   inc(j);
 end;


end;
0
 
geobulCommented:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Text := StringReplace(Memo1.Text, Chr(13) + Chr(10), ' ', [rfReplaceAll]);
  Memo1.Text := StringReplace(Memo1.Text, ' ', '', [rfReplaceAll]);
end;
0
 
geobulCommented:
Wow, I react really slow today :-)
0
 
Wim ten BrinkCommented:
Well, okay. Some pretty fast code that strips unwanted characters faster than StringReplace:

type
  TSkipChars = set of char;

function StripChars( const Value: string; SkipChars: TSkipChars ): string;
var
  I, J: Integer;
  Max: Integer;
begin
  Result := Value;
  Max := Length( Value ); // Avoids recalculating the length.
  I := 1;
  while ( I <= Max ) and not ( Result[ I ] in SkipChars ) do
    Inc( I );
  if ( I <= Max ) then begin
    J := I + 1;
    while ( J <= Max ) do begin
      if not ( Result[ J ] in SkipChars ) then begin
        Result[ I ] := Result[ J ];
        Inc( I );
      end;
      Inc( J );
    end;
  end;
  SetLength( Result, I - 1 );
end;

Yes, it looks complex. It took me over 10 minutes to write so it really must be complex... :-)
50 points for the person who finds a bug in that piece of code of mine... ;-)
0
 
Wim ten BrinkCommented:
Yes, Geo... You're slow today. Old age? :-)

About that function of mine, call it like:
  Memo1.Lines.Text := StripChars( Memo1.Lines.Text, [ #10, #13, #32, '.', ',' ] ) );

However, keep in mind that the line length of a memo isn't endless. Very long strings are either cut off at the end or split in multiple lines. I'm not sure exactly about the maximum line length of a TMemo and TRichBox but it's less than a TStringist can have, per line. A memo or richtext component in Delphi doesn't have a real stringlist connected to it. It just has some stringlist-compatible object linked to the Windows control. It's the Windows control that enforces this limit. The stringlist used by the memo is the TMemoStrings class. I'm not sure about the maximum line length of a Memo, but think it's around 1024, since that's the limit of the Delphi editor.
0
 
geobulCommented:
Alex, exactly, ooold age combined with slooow internet connection :-)
0
 
Pierre CorneliusCommented:
Howzit Alex,

I couldn't find a bug, but here's a more "english" (as opposed to greek... hehehe) version of your solution:

function PCStripChars( const Value: string; SkipChars: TSkipChars ): string;
var
  I, J: Integer;
  Max: Integer;
begin
  Result := Value;
  Max := Length( Value ); // Avoids recalculating the length.
  j:= 0;

  for i:= 1 to Max do
    if NOT (Value[i] in SkipChars)
    then begin
      Inc(j);
      result[j]:= Value[i];
    end;
  SetLength(result,j);
end;

Speedwise, it results in the same as your function.
0
 
Pierre CorneliusCommented:
Avg time "English" = 0.2083 milliseconds

avg time "Greek" = 0.2173 milliseconds
0
 
Wim ten BrinkCommented:
True, same result. You're using a for-next loop, which is where you gain more speed. :-) Still, we're talking about a 1% difference on a millisecond. :-P
I'll give you (or anyone else) 500 points (in a new topic) if you manage to create a function that's at least twice as fast as mine. :-)
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_21165246.html for the challenge...
0
 
DragonSlayerCommented:
Not exactly that fast... maybe 30% faster (based on a 2mb text file, averaged over 10,000 runs):

function MyStrip(const sValue: string): string;
var
  Max: Integer;
  i, j: Integer;
begin
  Max := Length(sValue);
  SetLength(Result, Max);
  j := 0;
  for i := 1 to Max do
    if sValue[i] in ['A' .. 'Z', 'a' .. 'z', '0' .. '9'] then
    begin
      Inc(j);
      Result[j] := sValue[i];
    end;
  SetLength(Result, j);
end;

Okay, so I cheated a bit in the code =p


DragonSlayer.
0
 
joncmoraCommented:
>> if sValue[i] in ['A' .. 'Z', 'a' .. 'z', '0' .. '9'] then

Even if the set is a parameter, it would still be faster because it has no Result := Value.  There is no need for such an assignment, SetLength(Result, Max) is perfect. Workshop_Alex's would suffer very much if most of the chars in Value are in SkipChars and Value is a very large string. :-)

Another improvement can be gained if we make Value a reference parameter. We know for sure that we're not changing it inside, right?
0
 
esoftbgCommented:
DragonSlayer,
your code does not work properly ....
0
 
DragonSlayerCommented:
Emil, what is wrong with it?
0
 
esoftbgCommented:
Your code is faster, but it eliminates many symbols as
','
'.'
':'
'!'
'@'
'#'
'$'
'%'
'&'
'*'
'('
')'
'-'
'+'
........
I think only improvement for your code makes it a perfect one:

function MyStrip(const sValue: string): string;
var
  Max: Integer;
  i, j: Integer;
begin
  Max := Length(sValue);
  SetLength(Result, Max);
  j := 0;
  for i := 1 to Max do
    if sValue[i] in [#0..#9, #11..#12, #14..#31, #33..#255] then
    begin
      Inc(j);
      Result[j] := sValue[i];
    end;
  SetLength(Result, j);
end;
0
 
Wim ten BrinkCommented:
@joncmora, if you look at http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_21165246.html then you'll see that I've actually organized a benchmark for my own stripchar function and for other alternative solutions. While my suggested solution might be slow, no one really managed to create a similar function that would be twice as fast in all situations. However, even if the memo is about 2500 lines long, these functions are just too fast to notice any real speed improvement. My method requires 9.425.846 processor ticks to handle 2500 strings. It's about twice as fast when it has to strip nothing or everything. On a 1 GHz machine you would have 1.000.000.000 processor ticks per second. Thus the speed is 1 millisecond for my method and about a half for the fastest one.

And since we would use:
  Memo1.Lines.Text := StripChars(Memo1.Lines.Text, [#10, #13]);
to remove all linebreaks, we just have only one single string manipulation. (We're not stripping each memo line since that way we would never see the linebreaks!)

The problem with Madshi's KillChar solution which uses this function header is simple:
  function KillChars( var str: string; killChrs: TSkipChars ): boolean;

The TMemo.Lines.Text property is just that! A property! Properties cannot be passed as var parameters to a function or procedure. If you would try to use:
  KillChars(Memo1.Lines.Text, [#10, #13]);

then the compiler will not compile this line of code, since you cannot pass a property as var parameter. Thus you would have to assign the property to a variable, pass the variable to the function and then assign the value back to the property. This additional overhead will just slow things down again.

One other solution would be this:

var
  I:Integer;
  Value: string;
begin
  Value := '';
  for I := 0 to Pred(Memo1.Lines.Count) do Value := Value + Memo1.Lines[I];
  Memo1.Lines.Text := Value;
end;

But this code would also be slower than just using one of the SkipChars versions in the other question.
0
 
joncmoraCommented:
I thought we're talking about a "fast" char stripper. So the source string will not be considered. If you're saying that the source will always be from <TString>.Text, then why not pass the <TString> instead. :-)
0

Featured Post

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

  • 6
  • 3
  • 3
  • +5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now