How to make TMemo treat new lines in Linux style? - delphi

I have a string that contains Linux style line breaks. Linux style is #13 while Windows style is #13#10.
I would like to show this string in a TMemo. Looks like TMemo accepts only Windows style and does not treat #13 as a new line.
Is the only way for TMemo to format new lines is to insert #10, or can I somehow ask TMemo to act in Linux style?

I would like to show this string in Memo. Looks like Memo accepts only Windows style and does not treat #$13 as new line.
That depends on how you give the string to the Memo.
The underlying Win32 EDIT control that TMemo wraps only supports #13#10 style line breaks internally.
If you assign the string to the TMemo.Text property, it will just pass the string as-is to the underlying Win32 control. So, the string will need to use Windows-style line breaks only.
However, if you assign the string to the TMemo.Lines.Text property instead, it will internally adjust all styles of line breaks to Windows-style, and then give the adjusted string to the Win32 control. So, in that regard, you can handle Linux-style and Windows-style line breaks equally.
Alternatively, the TStringList class supports parsing all styles of line breaks (when its LineBreak property matches the sLineBreak constant, which it does by default). So, another option would be to first assign the string to the TStringList.Text property, and then you can assign the resulting list to the TMemo.Lines property.

Actually Linux style is #10, not #13 (#13 is MacOS style, AFAIK). Also, note that it's #10 and not #$10 (which is #16).
The easiest way would be to replace the line ends on load/save, ie. instead of
Memo.Lines.LoadFromFile(FileName)
or
Memo.Lines.Text := STR;
do
uses System.IOUtils;
Memo.Lines.Text := TFile.ReadAllText(FileName,TEncoding.UTF8).Replace(#13#10,#13).Replace(#10,#13).Replace(#13,#13#10)
or
Memo.Lines.Text := STR.Replace(#13#10,#13).Replace(#10,#13).Replace(#13,#13#10)
and instead of
Memo.Lines.SaveToFile(FileName)
or
STR := Memo.Lines.Text
do
uses System.IOUtils;
TFile.WriteAllText(Memo.Lines.Text.Replace(#13#10,#13),TEncoding.UTF8)
or
STR := Memo.Lines.Text.Replace(#13#10,#13)
Of course, you should replace the TEncoding.UTF8 with the appropriate encoding you want to use.

Related

How to get rid of the built-in Paste shortcut in TRichEdit?

In a 32-bit VCL Application in Windows 10 in Delphi 11 Alexandria, I have a TRichEdit control. (Please note that the TRichEdit class in Delphi 11 Alexandria differs from previous Delphi versions).
Now, it seems that TRichEdit has a BUILT-IN Paste command and Shortcut: When I press CTRL+V, then the clipboard content gets inserted (image, formatted text).
So far, so good. But to allow the user to paste PLAIN TEXT (i.e., unformatted text) explicitly - even if there is formatted text on the clipboard, I have created a "Paste Plain Text" menu item command:
procedure TForm1.menuitemPastePlainTextClick(Sender: TObject);
begin
var ClipboardPlainText := Vcl.Clipbrd.Clipboard.AsText;
RichEdit1.SelText := ClipboardPlainText;
end;
I have assigned the shortcut SHIFT+CTRL+V to this command. (This shortcut is widely used among many applications for pasting unformatted text). However, when I type SHIFT+CTRL+V in RichEdit1, the FORMATTED text from the clipboard is pasted! Obviously, a BUILT-IN SHIFT+CTRL+V command in RichEdit1 has a higher priority than my custom shortcut.
So, how can I get rid of the built-in SHIFT+CTRL+V command in RichEdit1 to paste Plain Text?

How to fetch japanese characters in Delphi 7

I have a problem with displaying Japanese Character , specifically Unicode character "5c" in my delphi application . I need to save the application names into the registry and then display it in some kind of popup.
I have narrowed down the problem to this code specifically :-
Var
Str : WideString;
Str2: WideString;
Str3 : WideString;
TntEdit5.Text := TntOpenDialog1.FileName; //correctly displayed
Str3 := TntEdit5.Text;
ShowMessage('Original =' + Str3);
Str := UTF8Encode(TntEdit5.Text) ;
ShowMessage('UTF8Encode =' + Str3);
Str2 := UTF8Decode(Str) ;
ShowMessage('UTF8Decode =' + Str3);
end;
I dont get the correct name in Str, Str2 and Str3 . So how to fetch the name in a string ?
I dont want to display the text but i want to use it to save to registry and other functions.
Instead of SHowMessage, I used MessageBoxW(Form1.Handle, PWChar( Str3 ), 'Path', MB_OK ); which gave me correct result.
But I want to use this string internally, like write the string into a file etc. How to do that ?
Thanks In Advance
The type of Str does not match the type of result of UTF8Encode - so the line Str := UTF8Encode damages data. Instead of Str you should declare and use variable with a datatype mathcing the one of Utf8Encode result.
Same is true for Str2 := UTF8Decode(Str) line with regard to wrong data type of Str parameter the. It should be replaced with another var of proper datatype.
Str3 is not declared, so the code won't even compile. Add the Str3: WideString; line.
ShowMessage does not work with UTF-16, so then you make your own popup function that does.
Make your own dialog containing Tnt unicode-aware Label to display the text. And your new ShowMessage-like function would set the label's caption and then display that dialog instead of stock unicode-unaware one.
You may look at http://blog.synopse.info/post/2011/03/05/Open-Source-SynTaskDialog-unit-for-XP%2CVista%2CSeven for exampel of such dialogs, but i don't know if they are UTF-16 aware on D7.
Another option is searching TnT Sources for a ready-made unicode-aware function like ShowMessage - there may be one, or not.
Yet another option is using Win32 API directly, namely the MessageBoxW function working with PWideChar variables for texts: see http://msdn.microsoft.com/en-us/library/windows/desktop/ms645505.aspx
#DavidHeffernan MessageBoxW needs a lot of boilerplate both due to using C-Strings and for giving too much flexibility. It may be considered kinda good replacement for MessageDlg but not so much for ShowMessage. Then i am sure that TnT has ShowMessage conversion and that implementing own dialog would be good for both application look-and-feel and topic-starter experience.
You may also switch from obsolete Delphi 7 to modern CodeTyphon that uses UTF-8 for strings out of the box. You should at very least give it a try.
To read and write WideString from registry using Delphi 7 RTL you can make two easy options:
Convert WideString to UTF8 AnsiString and save it via TRegistry.WriteString and do back conversion on reading.
Save WideString as binary data: Cardinal(Length) followed by array of WideChar using TRegistry.WriteBinaryData
You can also use function RegReadWideString(const RootKey: DelphiHKEY; const Key, Name: string): WideString; and RegWriteWideString courtesy of http://jcl.sf.net
Whatever approach you'd choose - you have to do your own class on top of TRegistry that would be uniformly implementing those new TYourNewRegistry.WriteWideString and TYourNewRegistry.ReadWideString methods, so that the string written would always be read back using the same method.
However, since you already got TNT installed - then look carefully inside,. there just should be ready-made unicode-aware class like TTntRegistry or something like that.

How to read a text file that contains 'NULL CHARACTER' in Delphi?

I have a text file that contains many NULL CHARACTERS and its encoding is UTF8.
I loaded the file using RichEdit1.Lines.LoadFromFile(FileName,Encoding) stoped after the first Null Character and it didn't load the rest of file.
Is there any help. How can I remove NULL Chars from a text file.
**BTW My text file encoding is UTF8.
Reading the file shouldn't be a problem. Rather, the problem is more likely when you try to store the data in a rich-edit control. Those controls don't accept arbitrary binary data. You need to ensure you only put text in that control.
Load the file into an ordinary string or stream:
var
s: string;
ss: TStringStream;
s := TFile.ReadAllText(FileName);
Then remove the invalid characters. #0 is the notation in Delphi to represent a null character. Ordinarily, we might use StringReplace to remove characters:
s := StringReplace(s, #0, '', [rfReplaceAll]);
However, it's not binary-safe; it stops at null characters. Instead, you'll need a different function for removing those characters. I've demonstrated that before. Call that function to adjust the string:
RemoveNullCharacters(s);
Finally, put the data in the rich-edit control:
ss := TStringStream.Create(s);
try
RichEdit1.Lines.LoadFromStream(ss, Encoding);
finally
ss.Free;
end;
Are you sure it is a UTF8 and not a UNICODE file? As you may know UNICODE is two bytes, where first one is a null character for non UNICODE languages, for example Chinese and the like.
Have you try to open the file with the IDE editor? Open it, select all the text (Ctrl+A) and copy (Ctrl+C) create a new empty text file and paste (Ctrl+V) the text.
Save the new file and try the RichEdit with this new file.

How to save TStringList with UNIX line endings?

I cannot figure how to save the lines of a TStringList using UNIX line endings (LF) instead of the default CRLF ones.
I've tried to use StringReplace() on the stringList.Text property without any success :-(
StringList.Text is a property that generates the text every time. So when you assign the modified text back to the stringlist, you will undo you changes. When you get the text again, the stringlist will just build a new string with its default linebreak character.
This character can be influenced by setting the LineBreak property of the stringlist.
The default value for LineBreak is the sLineBreak constant, which can be either #13#10 on Windows or #10 on Linux or #13 on Mac.
Otherwise, if you save StringList.Text in a string variable, you can use StringReplace to change that string, or even better, use AdjustLineBreaks.
One more possibility is to use Jedi Code Library ( http://jcl.sf.net ) with split/join functionality in their version of string list.
var so : TJclStringList; // PODO style, requires finally-free-end
si : iJclStringList; // ref-counted interface for method chaining (aka Fluent API style)
s : String;
...
s := so.Join(^J);
s := si.Join(^J);

Delphi Copy Memo to Richedit problem

I am having a problem copying the contents of a memo to a richedit component.
I thought it would be
Richedit.text := memo.text;
However if I use this the Richedit starts a new line when the memo text wraps to a new a new line (not CR/LF) but just wrapping. The richedit also starts a new line when the memo starts a new line which is fine.
Anyone got any idea's how to copy the text from a memo into the richeditbox without the lines breaking in the Richedit when the memo text wraps
Thanks
Colin
When I do
RichEdit1.Text := Memo1.Text
the virtual "line-breaks" of the Memo1 are not magically converted to line-breaks (CRLF) in the RichEdit, and they shouldn't be. These "line-breaks" are not stored in the memo text buffer. Indeed, the official Embarcadero documentation states
Set WordWrap to true to make the edit control wrap text at the right margin so it fits in the client area. The wrapping is cosmetic only. The text does not include any return characters that were not explicitly entered.
Anyhow, an alternative way is to do
RichEdit1.Lines.Assign(Memo1.Lines);
although this will preserve the virtual line-breaks, as commented below.
Update
Most likely you have some other strangeness (bug) in your code, or you have phrased your question in a too vague manner. However, to eliminate the risk of any problem with the VCL wrappers, try this:
procedure TForm4.FormClick(Sender: TObject);
var
buf: PChar;
const
MAX_BUF_SIZE = 65536;
begin
GetMem(buf, MAX_BUF_SIZE * sizeof(char));
Memo1.Perform(WM_GETTEXT, MAX_BUF_SIZE, buf);
RichEdit1.Perform(WM_SETTEXT, 0, buf);
FreeMem(buf);
end;
As a dirty hack, could you switch off word wrap on your memo then do the assignment and then switch word wrap back on? It's a nasty hack but it might do the trick for you if there is some odd behaviour.

Resources