Question

I am generating a comma separated list of names in a string eg

Mr John Blue, Miss A Green, Mr Posh Hyphenated-Surname, Mr Fred Green, Miss Helen Red, Ms Jean Yellow

I now want to display them in a memo box that will hold 50 characters on each line so that as many names as possible (and their trailing comma) appear on each line. so the above should look like

Mr John Blue, Miss A Green,
Mr Posh Hyphenated-Surname, Mr Fred Green,
Miss Helen Red, Ms Jean Yellow

I've played with

Memo1.text := WrapText(Mystring,50)

but it broke lines at spaces between forename and surnames and I tried

Memo1.text := WrapText(MyString, slinebreak, ',' ,50) 

to force it to break only after a comma but that broke at spaces as well as commas. Both also tended to break at a hyphen and I note from Rob Kennedy's reply to a similar question that embedded quotes cause problems with Wrap() so a name like Mr John O'Donald would cause problems.

I even tried rolling my own function by counting characters and looking for commas but got bogged down in multiple nested IFs (Too embarassed to show the dreadful code for that!)

Can anyone offer any help or code showing how this can be done?

PS I have looked at

  • 'Word wrap in TMemo at a plus (+) char'
  • 'How do I split a long string into “wrapped” strings?'
  • 'Find a certain word in a string, and then wrap around it'

and other similar posts but none seem to match what I am looking for.

Was it helpful?

Solution

Set Memo1.WordWrap:=False;

There are many solutions, I show here just one.
But take care :
If you are using it with large amounts of data then the execution is quite slow

procedure TForm1.AddTextToMemo(needle,xsSrc:string);
var
xsNew:string;
mposOld,mposNew:integer;
start:byte;
begin
xsNew:=xsSrc;
repeat
  repeat
   mposOld:=mposNew;
   mposNew:=Pos(needle,xsSrc);
   if mposNew>0 then xsSrc[mposNew]:='*';
  until (mposNew > 50) OR (mposNew = 0);
  if  mposOld > 0  then begin
     if xsNew[1] = ' ' then start := 2 else start := 1;
     if mposNew = 0 then mposOld:=Length(xsNew);
     Memo1.Lines.Add(copy(xsNew,start,mposOld));
     if mposNew = 0 then exit;
     xsNew:=copy(xsNew,mposOld+1,Length(xsNew)-mposOld);
     xsSrc:=xsNew;
     mposNew:=0;
  end else xsSrc:='';
until xsSrc = '';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Clear;
AddTextToMemo(',','Mr John Blue, Miss A Green, Mr Posh Hyphenated-Surname, '+
                  'Mr Fred Green, Miss Helen Red, Ms Jean Yellow');
end;

UPDATE

if you have a small amount of data here is fast and easy to read.

...
var
 Form1: TForm1;
 NameList: TStrings;

...
 NameList := TStringList.Create;
...

procedure TForm1.AddTextToMemoB(needle,xsSrc:string);
var
xsNew:string;
i:integer;
sumLen:byte;

begin
xsNew:=''; sumLen:=0;
nameList.Text:=StringReplace(xsSrc,needle,needle+#13#10,[rfReplaceAll]);
for i := 0 to nameList.Count - 1 do begin
  sumLen:=SumLen+Length(nameList[i]);
  if i < nameList.Count - 1 then begin
    if (sumLen + Length(nameList[i+1]) > 50) then begin
       if xsNew='' then xsNew:=nameList[i];
       Memo1.Lines.Add(xsNew);
       xsNew:='';
       sumLen:=0;
    end else if xsNew='' then xsNew:=nameList[i]+nameList[i+1] else   
                              xsNew:=xsNew+nameList[i+1];
  end else Memo1.Lines.Add(xsNew);
end; // for
end;

OTHER TIPS

I haven't tested it, but something along the following lines ought to do the trick.

for LCh in S do
begin
  case LCh of
    ',' : //Comma completes a word
    begin
      LWord := LWord + LCh;
      if  (LLine <> '') and //Don't wrap if we haven't started a line
          ((Length(LLine) + Length(LWord)) > ALineLimit) then
      begin
        //Break the current line if the new word makes it too long
        AStrings.Add(LLine);
        LLine := '';
      end;
      if (LLine <> ' ') then LLine := LLine + ' '; //One space between words
      LLine := LLine + LWord;
      LWord := '';
    end;
  else
    if (LWord = '') and (LCh in [' ', #9]) then
    begin
      //Ignore whitespace at start of word.
      //We'll explicitly add one space when needed.
      //This might remove some extraneous spaces.
      //Consider it a bonus feature.
    end else
    begin
      LWord := LWord + LCh;
    end;
  end;
end;

//Add the remainder
if  (LLine <> '') and //Don't wrap if we haven't started a line
    ((Length(LLine) + Length(LWord)) > ALineLimit) then
begin
  //Break the current line if the new word makes it too long
  AStrings.Add(LLine);
  LLine := '';
end;
if (LLine <> ' ') then LLine := LLine + ' '; //One space between words
LLine := LLine + LWord;
AStrings.Add(LLine);

Of course you may have noted the duplication that should be moved to a sub-routine.
Tweak away to your hearts content.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top