質問
私はシリアルポートに取り組んでおり、8ビットデータでいくつかのハードウェアにデータを送受信しています。比較を容易にするために文字列として保存したいのですが、プリセットデータは文字列または16進数形式でxmlファイルに保存されます。ANSI エンコーディングである Encoding.Default を使用する場合にのみ、8 ビット データが適切に変換され、簡単に元に戻すことができることがわかりました。ASCII エンコードは 7 ビット データに対してのみ機能し、1 ~ 255 の文字を使用しているため、UTF8 や UTF7 もうまく機能しません。Encoding.Default は問題ありませんが、MSDN で読んだところ、これは OS のコードページ設定に依存しているため、構成されているコードページが異なると動作が異なる可能性があります。私は Encoding を使用して GetBytes() と GetString を頻繁に使用していますが、どのような構成でも常に機能するフェイルセーフで移植可能なメソッドが必要です。これに関するアイデアやより良い提案はありますか?
解決
Latin-1 別名 ISO-8859-1 別名コードページ 28591 は、128 ~ 255 の範囲の値を変更せずにマップするため、このシナリオに便利なコードページです。以下は交換可能です。
Encoding.GetEncoding(28591)
Encoding.GetEncoding("Latin1")
Encoding.GetEncoding("iso-8859-1")
次のコードは、Latin1 の場合、Encoding.Default とは異なり、0 ~ 255 の範囲のすべての文字が変更されずにマップされるという事実を示しています。
static void Main(string[] args)
{
Console.WriteLine("Test Default Encoding returned {0}", TestEncoding(Encoding.Default));
Console.WriteLine("Test Latin1 Encoding returned {0}", TestEncoding(Encoding.GetEncoding("Latin1")));
Console.ReadLine();
return;
}
private static bool CompareBytes(char[] chars, byte[] bytes)
{
bool result = true;
if (chars.Length != bytes.Length)
{
Console.WriteLine("Length mismatch {0} bytes and {1} chars" + bytes.Length, chars.Length);
return false;
}
for (int i = 0; i < chars.Length; i++)
{
int charValue = (int)chars[i];
if (charValue != (int)bytes[i])
{
Console.WriteLine("Byte at index {0} value {1:X4} does not match char {2:X4}", i, (int) bytes[i], charValue);
result = false;
}
}
return result;
}
private static bool TestEncoding(Encoding encoding)
{
byte[] inputBytes = new byte[256];
for (int i = 0; i < 256; i++)
{
inputBytes[i] = (byte) i;
}
char[] outputChars = encoding.GetChars(inputBytes);
Console.WriteLine("Comparing input bytes and output chars");
if (!CompareBytes(outputChars, inputBytes)) return false;
byte[] outputBytes = encoding.GetBytes(outputChars);
Console.WriteLine("Comparing output bytes and output chars");
if (!CompareBytes(outputChars, outputBytes)) return false;
return true;
}
他のヒント
代わりにバイト配列を使用しないのはなぜでしょうか?テキスト手法で発生する可能性のあるエンコードの問題は発生しません。
代わりにバイト配列を使用する必要があると思います。比較のために、次のような方法を使用できます。
static bool CompareRange(byte[] a, byte[] b, int index, int count)
{
bool res = true;
for(int i = index; i < index + count; i++)
{
res &= a[i] == b[i];
}
return res;
}
Windows-1255 のヘブライ語コードページを使用します。8ビットです。
エンコーディング enc = Encoding.GetEncoding("windows-1255");
あなたが「1-255」と書いたとき、私はあなたを誤解しました。コードページ 1255 の文字を参照しているのだと思いました。
Base64 エンコードを使用して、バイトから文字列に変換したり、その逆を行うことができます。そうすれば、コード ページや奇妙な文字の問題がなく、16 進数よりもスペース効率が良くなります。
byte[] toEncode;
string encoded = System.Convert.ToBase64String(toEncode);