Solved

Remove all space, line breaks and paragrahs from text

Posted on 2004-10-12
20
2,231 Views
Last Modified: 2010-04-05
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
Comment
Question by:wildzero
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 3
  • 3
  • +5
20 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12285610
Memo.Lines.Text := StringReplace(Memo.Lines.Text, #13#10, '', [rfReplaceAll]);

Tried that already? :-)
0
 
LVL 12

Expert Comment

by:esoftbg
ID: 12285647
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
 
LVL 17

Accepted Solution

by:
Wim ten Brink earned 125 total points
ID: 12285659
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!

 
LVL 10

Author Comment

by:wildzero
ID: 12285668
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
 
LVL 6

Expert Comment

by:Amir Azhdari
ID: 12285702
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
 
LVL 17

Expert Comment

by:geobul
ID: 12285708
procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Text := StringReplace(Memo1.Text, Chr(13) + Chr(10), ' ', [rfReplaceAll]);
  Memo1.Text := StringReplace(Memo1.Text, ' ', '', [rfReplaceAll]);
end;
0
 
LVL 17

Expert Comment

by:geobul
ID: 12285728
Wow, I react really slow today :-)
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12285730
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
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12285829
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
 
LVL 17

Expert Comment

by:geobul
ID: 12286348
Alex, exactly, ooold age combined with slooow internet connection :-)
0
 
LVL 14

Expert Comment

by:Pierre Cornelius
ID: 12286880
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
 
LVL 14

Expert Comment

by:Pierre Cornelius
ID: 12287029
Avg time "English" = 0.2083 milliseconds

avg time "Greek" = 0.2173 milliseconds
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12288258
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
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12289989
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
 

Expert Comment

by:joncmora
ID: 12295543
>> 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
 
LVL 12

Expert Comment

by:esoftbg
ID: 12295599
DragonSlayer,
your code does not work properly ....
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12295628
Emil, what is wrong with it?
0
 
LVL 12

Expert Comment

by:esoftbg
ID: 12295981
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
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12337378
@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
 

Expert Comment

by:joncmora
ID: 12345008
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

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

724 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question