如何在 C# 中编组 utf-8 字符串

本文关键字:utf-8 字符串 | 更新日期: 2023-09-27 18:33:59

有问题的函数是Sqlite原生C API的一部分,但答案应该是通用的。我很惊讶我找不到答案。

现有代码如下所示,但仅处理 8 位 ANSI。

// wrapper to handle marshalling and avoid nulls
public static string sqlite3_column_text_wrapper(IntPtr pstmt, int iCol) {
  var ptr = sqlite3_column_text(pstmt, iCol);
  if (ptr == IntPtr.Zero) return "";
  else return Marshal.PtrToStringAnsi(ptr);
}
// wrapper to handle marshalling and avoid nulls // TODO: utf
public static string sqlite3_column_text_wrapper_utf(IntPtr pstmt, int iCol) {
  var ptr = sqlite3_column_text(pstmt, iCol);
  if (ptr == IntPtr.Zero) return "";
  else return Marshal.PtrToStringAnsi(ptr);
}
[DllImport("sqlite3.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr sqlite3_column_text(IntPtr pstmt, int iCol);

问题是如何对 utf-8 做同样的事情,最好不必分配缓冲区并复制数据两次。

肯定有"一条最好的方法"吗?


我发现这个:C#回调接收UTF8字符串,它使用MultiByteToWideChar(两次)和StringBuilder。也许是答案。


一个答案提出了一个不安全的解决方案。这使得应用程序无法验证,如果任何其他解决方案可用,则价格太高。请不要不安全。

如何在 C# 中编组 utf-8 字符串

这个怎么样:

    /// <summary>
    /// Converts a byte pointer to a UTF8 encoded string.
    /// </summary>
    /// <param name="bytePtr">The byte PTR.</param>
    /// <returns></returns>
    public static unsafe string BytePtrToStringUTF8(byte* bytePtr)
    {
        if (bytePtr == null) return null;
        if (*bytePtr == 0) return string.Empty;
        var byteBuffer = new List<byte>(1024);
        var currentByte = default(byte);
        while (true)
        {
            currentByte = *bytePtr;
            if (currentByte == 0)
                break;
            byteBuffer.Add(currentByte);
            bytePtr++;
        }
        return Encoding.UTF8.GetString(byteBuffer.ToArray());
    }