Search code examples
regexstringdelphiword-wrap

Word wrap a Delphi string to a certain length using commas not spaces?


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.


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;