我从一个文件读取一个字节数组:
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);
请帮忙!
答案 0 :(得分:4)
物料清单是可选的。您无法使用它们来可靠地检测编码。即使有BOM,使用它来区分UTF和代码页编码也是有问题的,因为字节序列通常也是有效的(如果没有意义)。例如。在Windows-1251中,0xFE 0xFF是“юя”。
即使您可以通过代码页编码告诉UTF,也无法告诉其他代码页。你可以分析整个文本并做出猜测,但这很容易出错并且不太实用。
所以,我建议你不要试图检测编码。相反,需要特定的编码,或添加一种机制来指定它。
对于来自不同字节顺序的trandscoding,例如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;