记事本++ .NET插件 - 获取当前缓冲区文本 - 编码问题

本文关键字:缓冲区 文本 编码 问题 获取 NET 插件 记事本 | 更新日期: 2023-09-27 18:21:14

我有一个.NET插件,需要获取当前缓冲区的文本。我找到了这个页面,它显示了一种方法:

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();
}

这很好,直到我们解决字符编码问题。我有一个在编码菜单中设置为"没有 BOM 的 UTF-8"的缓冲区,我将该文本写入文件:

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);

这显示"4"表示"没有BOM的UTF-8"和"ASCII"的"0",但我找不到记事本++或Scintilla认为这些值应该代表什么。

所以我有点迷茫下一步该去哪里(窗户不是我的自然栖息地(。有人知道我做错了什么,或者如何进一步调试它吗?

谢谢。

记事本++ .NET插件 - 获取当前缓冲区文本 - 编码问题

删除 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');
    }
}

替代方法:

UTF-8字符损坏的原因是这一行。

Win32.SendMessage(curScintilla, SciMsg.SCI_GETTEXT, length, sb);

..使用 [MarshalAs(UnmanagedType.LPStr)] 读取字符串,在解码字符串 (MSDN( 时使用计算机的默认 ANSI 编码。这意味着你会得到一个每字节一个字符的字符串,对于多字节 UTF-8 字符,它会中断。

现在,要将原始 UTF-8 字节保存到磁盘,您只需在写入文件时使用相同的默认 ANSI 编码:

File.WriteAllText(@"C:'Users'davet'BBBBBB.txt", sb.ToString(), Encoding.Default);