将字节数组转换为给定编码的字符串

我从一个文件读取一个字节数组:

auto text = cast(immutable(ubyte)[]) read("test.txt");

我可以使用以下函数获取字符编码的类型:

enum EncodingType {ANSI, UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE}

EncodingType DetectEncoding(immutable(ubyte)[] data){
  switch (data[0]){
    case 0xEF:
      if (data[1] == 0xBB && data[2] == 0xBF){
        return EncodingType.UTF8;
      } break;
    case 0xFE:
      if (data[1] == 0xFF){
        return EncodingType.UTF16BE;
      } break;
    case 0xFF:
      if (data[1] == 0xFE){
        if (data[2] == 0x00 && data[3] == 0x00){
          return EncodingType.UTF32LE;
        }else{
          return EncodingType.UTF16LE;
        }
      }
    case 0x00:
      if (data[1] == 0x00 && data[2] == 0xFE && data[3] == 0xFF){
        return EncodingType.UTF32BE;
      }
    default:
      break;
  }
  return EncodingType.ANSI;
}

我需要一个采用字节数组并返回文本字符串(utf-8)的函数。 如果文本以UTF-8编码,那么转换是微不足道的。 同样,如果编码为系统的UTF-16或UTF-32本机字节顺序。

string TextDataToString(immutable(ubyte)[] data){
  import std.utf;
  final switch (DetectEncoding(data[0..4])){
    case EncodingType.ANSI:
      return null;/*???*/
    case EncodingType.UTF8:
      return cast(string) data[3..$];
    case EncodingType.UTF16LE:
      wstring result;
      version(LittleEndian) { result = cast(wstring) data[2..$]; }
      version(BigEndian) { result = "";/*???*/ }
      return toUTF8(result);
    case EncodingType.UTF16BE:
      return null;/*???*/
    case EncodingType.UTF32LE:
      dstring result;
      version(LittleEndian) { result = cast(dstring) data[4..$]; }
      version(BigEndian) { result = "";/*???*/ }
      return toUTF8(result);
    case EncodingType.UTF32BE:
      return null;/*???*/
  }
}

但我无法弄清楚如何将字节数组与ANSI编码文本(例如,windows-1251)或UTF-16/32转换为非本地字节顺序。 我用/*???*/勾选了代码中的适当位置。

因此,下面的代码应该可以使用任何文本文件的编码:

string s = TextDataToString(text);
writeln(s);

请帮忙!


BOM是可选的。 您不能使用它们来可靠地检测编码。 即使有BOM,使用它来区分UTF和代码页编码也是有问题的,因为这些字节序列通常也是有效的(如果是无意义的)。 例如,在Windows-1251中,0xFE 0xFF是“юя”。

即使您可以通过代码页编码告诉UTF,也无法告诉其他代码页。 你可以分析整个文本并做出猜测,但这是超级错误倾向,不太实际。

所以,我建议你不要尝试检测编码。 相反,需要一个特定的编码,或者添加一个机制来指定它。


对于来自不同字节顺序的交易编码,例如UTF16BE:

import std.algorithm: map;
import std.bitmanip: bigEndianToNative;
import std.conv: to;
import std.exception: enforce;
import std.range: chunks;

alias C = wchar;
enforce(data.length % C.sizeof == 0);
auto result = data
    .chunks(C.sizeof)
    .map!(x => bigEndianToNative!C(x[0 .. C.sizeof]))
    .to!string;
链接地址: http://www.djcxy.com/p/78435.html

上一篇: Converting a byte array to a string given encoding

下一篇: How to convert from character positions to byte postions in UTF