我有一大串 RTF 格式的数据。格式正确,将其放入 ANSI 文本文件中,将其重命名为 *.rtf,写字板将正确显示它。
该字符串本质上是 std:wstring,而不是 TUnicodeString
如果我执行以下操作,文本将正确显示并具有正确的颜色格式等:
TStringStream *Stream = new TStringStream(String(MyString.c_str(), MyString.size())) ;
Stream->Position = 0 ;
RichEdit1->PlainText = false ;
RichEdit1->Lines->LoadFromStream(Stream) ;
delete Stream ;
一切都好,它可以工作,但我正在考虑避免创建字符串时发生的 memcpy,这将节省一些特别大的字符串的资源。
我的目标是创建一个
TCustomMemoryStream
后代,它以 MyString 作为输入,并在构造过程中通过调用 SetPointer((void*)MyString.c_str(), MyString.Length() * 2 /*Size in bytes*/)
使用其内部内存。
如果小心处理,这可以节省 memcpy(MyString 必须比 Stream 等更长寿),并且这是一个简单快速的实现。
可悲的是..它无法正常工作,我似乎不明白为什么?我有一个可行的解决方案,我可以继续..但这让我烦恼..所以请启发我。
测试的实现略有不同,但归根结底是相同的:
TMemoryStream *Stream = new TMemoryStream() ;
Stream->Write((void*)MyString.c_str(), MyString.length() * 2 /*Bytes*/) ;
Stream->Position = 0 ;
RichEdit1->PlainText = false ;
RichEdit1->Lines->LoadFromStream(Stream) ;
delete Stream ;
RichEdit 无法显示格式化文本。相反,它显示纯文本(字符间隔开)。我理解这是编码不正确的情况,这是有道理的。
所以我告诉 LoadFromStream() 使用什么编码:
TMemoryStream *Stream = new TMemoryStream() ;
Stream->Write((void*)MyString.c_str(), MyString.length() * 2 /*Bytes*/) ;
Stream->Position = 0 ;
RichEdit1->PlainText = false ;
RichEdit1->Lines->LoadFromStream(Stream, TEncoding::Unicode) ;
delete Stream ;
文本现在可以正确显示 但是仍然是纯文本,rtf 未被解析。 我不明白为什么,看起来文本完整地到达了,复制粘贴到文本文件中,与早期的 rtf 文件相比,内容是相同的。
我想编码可能需要 BOM 才能正常工作(因为这是
TEncoding::Unicode
中的默认值),所以我添加了一个用于测试:
TMemoryStream *Stream = new TMemoryStream() ;
WORD BOM = 0xFEFF ;
Stream->Write((void*)&BOM, 2) ;
Stream->Write((void*)MyString.c_str(), MyString.length() * 2 /*Bytes*/) ;
Stream->Position = 0 ;
RichEdit1->PlainText = false ;
RichEdit1->Lines->LoadFromStream(Stream, TEncoding::Unicode) ;
delete Stream ;
但这没有什么区别。所以我尝试相反(通过不需要BOM的
TEncoding
):
TMemoryStream *Stream = new TMemoryStream() ;
Stream->Write((void*)MyString.c_str(), MyString.length() * 2 /*Bytes*/) ;
Stream->Position = 0 ;
RichEdit1->PlainText = false ;
TUnicodeEncoding *Encoding = new TUnicodeEncoding(false /*UseBOM*/) ;
RichEdit1->Lines->LoadFromStream(Stream, Encoding) ;
delete Encoding ;
delete Stream ;
遗憾的是,仍然只是纯文本
我在测试应用程序中尝试了一些其他的东西,加载到TMemo,保存到流,加载到RichEdit等(有各种结果),我还尝试在TStringStream构造期间设置编码,但结果很奇怪,但我不知道不想把这个问题弄乱了。
我想了解为什么 TRichEdit 无法解析 rtf,即使它似乎正确获取所有数据,因为它以纯文本方式显示
我目前正在使用 C++ Builder 12
我的目标是创建一个
后代,以TCustomMemoryStream
作为输入并使用其内部记忆MyString
TPointerStream
。
将我想了解为什么 TRichEdit 无法解析 rtf,即使它似乎正确获取所有数据,因为它以纯文本方式显示
TStringStream
存储到内存中时,
TEncoding::Default
默认使用 String
。 IOW,它实际上将 String
转换为指定(或在本例中为默认)编码,然后存储转换后的字节。
当
TRichEdit::Lines::LoadFromStream()
方法加载 TStream
时,如果没有显式指定 TEncoding::Default
并且流数据中不存在 BOM,它也会假定 TEncoding
。
这就是您的
TStringStream
测试成功的原因。您的 String
已转换为 LoadFromStream()
期望的编码。
但是,在 Windows 上
TEncoding::Default
与 TEncoding::ANSI
相同。如果您将 UTF-16 存储在 TMemoryStream
中,则与 TEncoding::ANSI
所期望的不匹配,因此您必须明确要使用的实际编码。
现在,当您明确指定编码时,事情仍然不起作用,因为当
PlainText
为 false 时,TRichEdit
在向自身发出 SF_RTF
窗口消息时使用 SF_UNICODE
without
EM_STREAMIN
。仅当 SF_UNICODE
为 true 时才使用 PlainText
(用 SF_TEXT
代替 SF_RTF
)。 RTF 是 7 位 ASCII 格式,并且 SF_RTF
无法处理 UTF-16(这也是您的 TStringStream
测试有效的原因)。
当
SF_RTF
失败时,TRichEdit
将使用 SF_TEXT
和 SF_UNICODE
再次尝试,这就是为什么您最终会得到纯文本版本的 RTF。
所以,简而言之,使用
PlainText=false
时不要使用UTF-16数据。如果您确实想使用 UTF-16 RTF,我认为您需要实现一个自定义 TConversion
后代并将其分配给 TRichEdit::DefaultConverter
属性。