UTF-8 byte []を文字列に変換する方法は?


932

UTF-8byte[]が含まれていることがわかっているファイルから読み込まれた配列があります。

一部のデバッグコードでは、それを文字列に変換する必要があります。これを行うライナーはありますか?

カバーの下では、それは単なる割り当てとmemcopyであるべきなので、それが実装されていなくても、それは可能であるべきです。


5
「単なる割り当てとメモリコピーである必要があります」:.NET文字列はUTF-16でエンコードされているため、不正解です。Unicode文字は、1つのUTF-8コード単位または1つのUTF-16コード単位の場合があります。別の2つはUTF-8コードユニットまたは1つのUTF-16コードユニット、別の3つはUTF-8コードユニットまたは1つのUTF-16コードユニット、別は4つのUTF-8コードユニットまたは2つのUTF-16コードユニット。memcopyは拡張できる可能性がありますが、UTF-8からUTF-16への変換を処理できません。
トムブロジェット2016年

回答:


1470
string result = System.Text.Encoding.UTF8.GetString(byteArray);

13
nullで終了する文字列はどのように処理されますか?
maazza

14
@maazzaは、理由は不明ですが、まったくありません。のように呼んでいSystem.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');ます。
Hi-Angel

15
@ Hi-Angel不明な理由は?nullで終了する文字列が一般的になった唯一の理由はC言語でした-そしてそれは歴史的な奇妙さ(nullで終了する文字列を処理するCPU命令)のためでした。.NETは、nullで終了する文字列(最終的には表示されなくなる)を使用するコードと相互運用する場合にのみ、nullで終了する文字列を使用します。文字列がNUL文字を含むことは完全に有効です。そしてもちろん、nullで終了する文字列はASCIIでは完全に単純ですが(最初のゼロバイトを取得するまでビルドするだけです)、UTF-8を含む他のエンコーディングはそれほど単純ではありません。
Luaan、2015年

4
UTF-8の美しい機能の1つは、短いシーケンスが長いシーケンスのサブシーケンスになることは決してないということです。したがって、nullで終了するUTF-8文字列は単純です。
プラグウォッシュ2015年

10
それが非ASCIIの場合は、開梱して頑張ってください。Convert.ToBase64Stringを使用するだけです。
Erik Bergstedt

323

この変換を行うには、少なくとも4つの異なる方法があります。

  1. エンコーディングのGetString
    ですが、それらのバイトに非ASCII文字が含まれている場合、元のバイトを取得することはできません。

  2. BitConverter.ToString
    出力は「-」で区切られた文字列ですが、文字列をバイト配列に戻す.NET組み込みメソッドはありません。

  3. Convert.ToBase64Stringを
    使用すると、出力文字列を簡単にバイト配列に変換できますConvert.FromBase64String
    注:出力文字列には、「+」、「/」、「=」を含めることができます。URLで文字列を使用する場合は、明示的にエンコードする必要があります。

  4. HttpServerUtility.UrlTokenEncodeを
    使用すると、出力文字列をバイト配列に簡単に変換できますHttpServerUtility.UrlTokenDecode。出力文字列はすでにURLフレンドリーです!欠点はSystem.Web、プロジェクトがWebプロジェクトでない場合は、アセンブリが必要になることです。

完全な例:

byte[] bytes = { 130, 200, 234, 23 }; // A byte array contains non-ASCII (or non-readable) characters

string s1 = Encoding.UTF8.GetString(bytes); // ���
byte[] decBytes1 = Encoding.UTF8.GetBytes(s1);  // decBytes1.Length == 10 !!
// decBytes1 not same as bytes
// Using UTF-8 or other Encoding object will get similar results

string s2 = BitConverter.ToString(bytes);   // 82-C8-EA-17
String[] tempAry = s2.Split('-');
byte[] decBytes2 = new byte[tempAry.Length];
for (int i = 0; i < tempAry.Length; i++)
    decBytes2[i] = Convert.ToByte(tempAry[i], 16);
// decBytes2 same as bytes

string s3 = Convert.ToBase64String(bytes);  // gsjqFw==
byte[] decByte3 = Convert.FromBase64String(s3);
// decByte3 same as bytes

string s4 = HttpServerUtility.UrlTokenEncode(bytes);    // gsjqFw2
byte[] decBytes4 = HttpServerUtility.UrlTokenDecode(s4);
// decBytes4 same as bytes

7
LINQ it:var decBytes2 = str.Split('-').Select(ch => Convert.ToByte(ch, 16)).ToArray();
drtf 2014

25

エンコーディングがわからない場合にバイト配列から文字列に変換する一般的なソリューション:

static string BytesToStringConverted(byte[] bytes)
{
    using (var stream = new MemoryStream(bytes))
    {
        using (var streamReader = new StreamReader(stream))
        {
            return streamReader.ReadToEnd();
        }
    }
}

3
ただし、これはバイトストリームにエンコーディングBOMがあるか、UTF-8であると想定しています。しかし、とにかくエンコーディングで同じことができます。エンコーディングがわからない場合、魔法のように問題を解決することはできません。
Sebastian Zander

12

定義:

public static string ConvertByteToString(this byte[] source)
{
    return source != null ? System.Text.Encoding.UTF8.GetString(source) : null;
}

使用:

string result = input.ConvertByteToString();

9

a byte[]をaに変換するのstringは簡単に見えますが、あらゆる種類のエンコーディングは出力文字列を台無しにする可能性があります。この小さな関数は、予期しない結果なしに機能します。

private string ToString(byte[] bytes)
{
    string response = string.Empty;

    foreach (byte b in bytes)
        response += (Char)b;

    return response;
}

Convert.FromBase64Stringでアンパックしたときに、メソッドを使用してSystem.FormatExceptionを受け取りました。
Erik Bergstedt

@ AndrewJEこれは、画像で使用されているような大きなバイト配列がある場合でも、計算にかかる時間です。
user3841581 2017年

7

(byte)b.ToString("x2")、出力の使用b4b5dfe475e58b67

public static class Ext {

    public static string ToHexString(this byte[] hex)
    {
        if (hex == null) return null;
        if (hex.Length == 0) return string.Empty;

        var s = new StringBuilder();
        foreach (byte b in hex) {
            s.Append(b.ToString("x2"));
        }
        return s.ToString();
    }

    public static byte[] ToHexBytes(this string hex)
    {
        if (hex == null) return null;
        if (hex.Length == 0) return new byte[0];

        int l = hex.Length / 2;
        var b = new byte[l];
        for (int i = 0; i < l; ++i) {
            b[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
        }
        return b;
    }

    public static bool EqualsTo(this byte[] bytes, byte[] bytesToCompare)
    {
        if (bytes == null && bytesToCompare == null) return true; // ?
        if (bytes == null || bytesToCompare == null) return false;
        if (object.ReferenceEquals(bytes, bytesToCompare)) return true;

        if (bytes.Length != bytesToCompare.Length) return false;

        for (int i = 0; i < bytes.Length; ++i) {
            if (bytes[i] != bytesToCompare[i]) return false;
        }
        return true;
    }

}

4

UnicodeEncodingクラスもあり、使用方法は非常に簡単です。

ByteConverter = new UnicodeEncoding();
string stringDataForEncoding = "My Secret Data!";
byte[] dataEncoded = ByteConverter.GetBytes(stringDataForEncoding);

Console.WriteLine("Data after decoding: {0}", ByteConverter.GetString(dataEncoded));

しかし、UTF-8ではありませんか?
david.pfx 2015

1
UnicodeEncodingこれまでで最悪のクラス名です。unicodeはエンコーディングではありません。そのクラスは実際にはUTF-16です。リトル・エンディアン版だと思います。
Nyerguds


2

byteArrFilenameファイルから読み取ったバイト配列を純粋なASCII形式のCスタイルのゼロ終了文字列に変換するLinqワンライナーは次のようになります。古いアーカイブ形式のファイルインデックステーブルなどを読み取るのに便利です。

String filename = new String(byteArrFilename.TakeWhile(x => x != 0)
                              .Select(x => x < 128 ? (Char)x : '?').ToArray());

'?'ここでは純粋なASCII以外のデフォルト文字として使用していますが、もちろん変更できます。確実に検出できるようにしたい場合は、'\0'代わりに使用TakeWhileしてください。最初にを使用すると、この方法で作成された文字列'\0'に入力ソースの値が含まれないようにすることができます。


2

BitConverterクラスを使用してa byte[]をに変換できますstring

var convertedString = BitConverter.ToString(byteAttay);

BitConverterクラスのドキュメントは、MSDNで見つかることがあります


1
これにより、バイト配列が各バイトを表す16進数の文字列に変換されます。これは、通常、バイトを文字列に変換するときに必要なことではありません。もしそうなら、それは別の質問です、たとえば、バイト配列を16進文字列に変換するにはどうすればよいですか?
CodeCaster 2017年

OPが要求したものではない

2

私の知る限り、与えられた答えはどれもnull終了での正しい動作を保証しません。誰かが私に別の方法を示すまで、私はこれを次のメソッドで処理するための独自の静的クラスを書きました:

// Mimics the functionality of strlen() in c/c++
// Needed because niether StringBuilder or Encoding.*.GetString() handle \0 well
static int StringLength(byte[] buffer, int startIndex = 0)
{
    int strlen = 0;
    while
    (
        (startIndex + strlen + 1) < buffer.Length // Make sure incrementing won't break any bounds
        && buffer[startIndex + strlen] != 0       // The typical null terimation check
    )
    {
        ++strlen;
    }
    return strlen;
}

// This is messy, but I haven't found a built-in way in c# that guarentees null termination
public static string ParseBytes(byte[] buffer, out int strlen, int startIndex = 0)
{
    strlen = StringLength(buffer, startIndex);
    byte[] c_str = new byte[strlen];
    Array.Copy(buffer, startIndex, c_str, 0, strlen);
    return Encoding.UTF8.GetString(c_str);
}

その理由は、startIndex私が特にbyte[]nullで終了する文字列の配列として解析する必要がある私が取り組んでいた例にありました。単純なケースでは無視しても問題ありません


私は実際にそうします。byteArr.TakeWhile(x => x != 0)ヌル終了問題を解決するための迅速かつ簡単な方法です。
Nyerguds 2017

1

hierは、エンコーディングに煩わ​​される必要がなかった結果です。ネットワーククラスで使用し、バイナリオブジェクトを文字列として送信しました。

        public static byte[] String2ByteArray(string str)
        {
            char[] chars = str.ToArray();
            byte[] bytes = new byte[chars.Length * 2];

            for (int i = 0; i < chars.Length; i++)
                Array.Copy(BitConverter.GetBytes(chars[i]), 0, bytes, i * 2, 2);

            return bytes;
        }

        public static string ByteArray2String(byte[] bytes)
        {
            char[] chars = new char[bytes.Length / 2];

            for (int i = 0; i < chars.Length; i++)
                chars[i] = BitConverter.ToChar(bytes, i * 2);

            return new string(chars);
        }

持っていませんでした。しかし、この機能は当社のネットワークでのバイナリ送信に使用されており、これまでのところ20TBが正しく再エンコードされました。したがって、この機能は私にとっては機能します:)
Marco Pardo

1

選択した回答に加えて、.NET35または.NET35 CEを使用している場合は、デコードする最初のバイトのインデックスとデコードするバイト数を指定する必要があります。

string result = System.Text.Encoding.UTF8.GetString(byteArray,0,byteArray.Length);

0

このコンソールアプリをお試しください:

static void Main(string[] args)
{
    //Encoding _UTF8 = Encoding.UTF8;
    string[] _mainString = { "Héllo World" };
    Console.WriteLine("Main String: " + _mainString);

    //Convert a string to utf-8 bytes.
    byte[] _utf8Bytes = Encoding.UTF8.GetBytes(_mainString[0]);

    //Convert utf-8 bytes to a string.
    string _stringuUnicode = Encoding.UTF8.GetString(_utf8Bytes);
    Console.WriteLine("String Unicode: " + _stringuUnicode);
}

0

同じ問題を解決するためにC#プログラミングにいくつかのアプローチがあるため、この投稿でいくつかの回答を見ましたが、それは完全な基本知識と見なすことができます。考慮する必要があるのは、純粋なUTF-8BOMを使用したUTF-8の違いだけです。です。

先週の私の仕事では、BOMを含むCSVファイルと純粋なUTF-8(BOMを含まない)を含むCSVを出力する1つの機能を開発する必要があります。各CSVファイルのエンコードタイプは、異なる非標準APIによって使用されます。 APIはBOMを使用してUTF-8を読み取り、その他のAPIはBOMを使用せずに読み取ります。私のアプローチを構築するには、「BOMなしのUTF-8とUTF-8の違いは何ですか?」を読んで、この概念に関するリファレンスを調査する必要があります。スタックオーバーフローのディスカッションとこのWikipediaのリンク「バイトオーダーマーク

最後に、両方のUTF-8エンコードタイプ(BOMとpureを使用)のC#プログラミングは、次の例のようにする必要があります。

//for UTF-8 with B.O.M., equals shared by Zanoni (at top)
string result = System.Text.Encoding.UTF8.GetString(byteArray);

//for Pure UTF-8 (without B.O.M.)
string result = (new UTF8Encoding(false)).GetString(byteArray);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.