Solved

Remove all space, line breaks and paragrahs from text

Posted on 2004-10-12
20
1,928 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
  • 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
 
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
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

758 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now