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

时间:2013-07-04 14:54:13

标签: c# .net plugins notepad++ scintilla

我有一个.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不是我的自然栖息地)。任何人都知道我错了什么,或者如何进一步调试它?

感谢。

2 个答案:

答案 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}}