Recent

Author Topic: The problem of splitting mixed strings from delphi to lazarus Chinese characters  (Read 3685 times)

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Here you get again my version and added a method for real linewidth calculations.

This method you can call to get the biggest pixel width of your current string input.
With that information you can easy calculate how much chars fit into one visual component by doing compontent.width div BiggestCharWidth = number of max chars per line, that is needed for the other method
Code: Pascal  [Select][+][-]
  1. function BiggestCharWidth(const AString: string; const AFont: TFont): Integer;
  2. var
  3.   Bmp: TBitmap;
  4.   i, LMax: Integer;
  5.   LChar: string;
  6. begin
  7.   Result := 0;
  8.   LMax := 0;
  9.   Bmp := TBitmap.Create;
  10.   try
  11.     Bmp.SetSize(1, 1);
  12.     Bmp.Canvas.Font.Assign(AFont);
  13.     for i := 1 to UTF8Length(AString) do
  14.       begin
  15.         LChar := UTF8Copy(AString, i, 1);
  16.         if Bmp.Canvas.TextWidth(LChar) > LMax then
  17.           LMax := Bmp.Canvas.TextWidth(LChar);
  18.       end;
  19.     Result := LMax;
  20.   finally
  21.     bmp.Free;
  22.   end;
  23. end;
Here the main split method, with extended parameters.
Code: Pascal  [Select][+][-]
  1. function CreateStringSplit(const AString: string; const ACharsPerLine, ALeadingSpace: Integer; const AStripControlChars, AKeepLineBreaks: Boolean; var AOutput: TStringList): Boolean;
  2. var
  3.   i: Integer; // loop counter
  4.   s, sLead: string; // temp string that be inserted into output
  5.   LChar: string; // current char
  6.   chars: Integer; // those keep track about used space, in bytes and chars
  7.   CanAddChar, IsLineBreak: Boolean; // Bool that represents if we add a char or replace current with a space
  8. begin
  9.   // create object if non-existant, beware to nil it where-ever you have declared it(!)
  10.   if (AOutput = nil) then
  11.     AOutput := TStringList.Create;
  12.   // clear current list
  13.   AOutput.Clear;
  14.   // initialize basics
  15.   sLead := '';
  16.   for i := 0 to ALeadingSpace do
  17.     sLead := sLead + ' ';
  18.   s := sLead;
  19.   chars := Length(sLead);
  20.   // loop over full string
  21.   for i := 1 to UTF8Length(AString) do
  22.     begin
  23.       // increment current used chars
  24.       Inc(chars);
  25.       // initialize state
  26.       CanAddChar := True;
  27.       // get current char from string
  28.       LChar := UTF8Copy(AString, i, 1);
  29.       // check if its a control char
  30.       if (AStripControlChars or AKeepLineBreaks) then
  31.         begin
  32.           // initialize state
  33.           IsLineBreak := False;
  34.           // do we found a control char?
  35.           if (CanAddChar and ((Ord(LChar[1]) < 32) or (Ord(LChar[1]) = 127))) then
  36.             begin
  37.               // is it a carriage return (CR) ?
  38.               if (AKeepLineBreaks and (Ord(LChar[1]) = 13)) then
  39.                 IsLineBreak := True;
  40.               // is it a linefeed (LF) ?  (if we already had CR, or one comes next, skip it)
  41.               if ((AKeepLineBreaks and (Ord(LChar[1]) = 10)) and ((Pred(i) > 0) and (Ord(UTF8Copy(AString, Pred(i), 1)[1]) <> 13)) and ((Succ(i) <= UTF8Length(AString)) and (Ord(UTF8Copy(AString, Succ(i), 1)[1]) <> 13))) then
  42.                 IsLineBreak := True;
  43.               // forbid usage of current char
  44.               if AStripControlChars or IsLineBreak then
  45.                 CanAddChar := False;
  46.             end;
  47.         end;
  48.       // we found a char to add
  49.       if CanAddChar then
  50.         begin
  51.           // add current char to the string
  52.           s := s + LChar;
  53.           // did we reached the limit?
  54.           if (chars >= ACharsPerLine) then
  55.             begin
  56.               // add current string to the string list
  57.               AOutput.Add(s);
  58.               // initialize basics
  59.               s := sLead;
  60.               chars := Length(s);
  61.             end;
  62.         end
  63.         // not allowed char found
  64.         else
  65.           // was the not allowed char a linebreak that we wanted to rescue?
  66.           if (AKeepLineBreaks and IsLineBreak) then
  67.             begin
  68.               // add current string to the string list
  69.               AOutput.Add(s);
  70.               // initialize basics
  71.               s := sLead;
  72.               chars := Length(s);
  73.             end
  74.             else
  75.               // replace control char with a space
  76.               s := s + ' ';
  77.     end;
  78.   // do not forget to append the last information to list
  79.   if (s <> '') then
  80.     AOutput.Add(s);
  81.   // exit method by telling a success state
  82.   Result := (AOutput.Count > 0);
  83. end;

My new signature in short explained:
AString = the main input string
ACharsPerLine = how many chars per line
ALeadingSpace = how much leading space
AStripControlChars = remove all control characters
AKeepLineBreaks = shall we keep linebreaks?
AOutput: = a TStringList as output

I hope you understand everything and be able to solve your problem now fully.
« Last Edit: January 16, 2023, 12:31:23 am by KodeZwerg »
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

jianwt

  • Full Member
  • ***
  • Posts: 164
Thanks to the help of the above several netizens, the problem has been solved.
Thank you very much.
« Last Edit: January 16, 2023, 01:57:47 am by jianwt »

 

TinyPortal © 2005-2018