我有一个.NET插件,需要获取当前缓冲区的文本。我找到了这个page,它显示了一种方法:
public static string GetDocumentText(IntPtr curScintilla)
{
int length = (int)Win32.SendMessage(curScintilla, SciMsg.SCI_GETLENGTH, 0, 0) + 1;
StringBuilder sb = new StringBuilder(length);
Win32.SendMessage(curScintilla, SciMsg.SCI_GETTEXT, length, sb);
return sb.ToString();
}
这很好,直到我们达到字符编码问题。我有一个在编码菜单中设置为“UTF-8无BOM”的缓冲区,我将该文本写入文件:
System.IO.File.WriteAllText(@"C:\Users\davet\BBBBBB.txt", sb.ToString());
当我打开该文件时(在记事本++中),编码菜单显示没有BOM的UTF-8,但ß
字符被破坏(ß)。
我能够找到当前缓冲区的编码:
int currentBuffer = (int)Win32.SendMessage(PluginBase.nppData._nppHandle, NppMsg.NPPM_GETCURRENTBUFFERID, 0, 0);
Console.WriteLine("currentBuffer: " + currentBuffer);
int encoding = (int) Win32.SendMessage(PluginBase.nppData._nppHandle, NppMsg.NPPM_GETBUFFERENCODING, currentBuffer, 0);
Console.WriteLine("encoding = " + encoding);
“UTF-8没有BOM”显示“4”,“ASCII”显示“0”,但我找不到记事本++或Scintilla认为这些值应该代表的内容。
所以我有点失去了下一步的去处(Windows不是我的自然栖息地)。任何人都知道我错了什么,或者如何进一步调试它?
感谢。
答案 0 :(得分:4)
删除StringBuilder修复了这个问题。
public static string GetDocumentTextBytes(IntPtr curScintilla) {
int length = (int) Win32.SendMessage(curScintilla, SciMsg.SCI_GETLENGTH, 0, 0) + 1;
byte[] sb = new byte[length];
unsafe {
fixed (byte* p = sb) {
IntPtr ptr = (IntPtr) p;
Win32.SendMessage(curScintilla, SciMsg.SCI_GETTEXT, length, ptr);
}
return System.Text.Encoding.UTF8.GetString(sb).TrimEnd('\0');
}
}
答案 1 :(得分:0)
替代方法:
UTF-8字符损坏的原因是这一行..
Win32.SendMessage(curScintilla, SciMsg.SCI_GETTEXT, length, sb);
..使用[MarshalAs(UnmanagedType.LPStr)]
读取字符串,File.WriteAllText(@"C:\Users\davet\BBBBBB.txt", sb.ToString(), Encoding.Default);
在解码字符串(MSDN)时使用计算机的默认ANSI编码。这意味着你得到一个每个字节有一个字符的字符串,它打破了多字节的UTF-8字符。
现在,要将原始的UTF-8字节保存到磁盘,只需在编写文件时使用相同的默认ANSI编码:
{{1}}