web-dev-qa-db-ja.com

手動でエンコードを指定せずにC#で文字列の一貫したバイト表現を取得する方法

手動で特定のエンコーディングを指定せずに、.NET(C#)でstringbyte[]に変換する方法を教えてください。

文字列を暗号化します。変換せずに暗号化することもできますが、ここでなぜエンコードが有効になるのかを知りたいです。

また、なぜエンコードを考慮に入れるべきなのでしょうか。単純に文字列が何バイトに格納されているのかを知ることはできませんか?文字エンコーディングに依存するのはなぜですか?

2055
Agnel Kurian

ここでの答えとは反対に、あなたはエンコードすることを心配する必要はありませんifバイトは解釈される必要はありません!

あなたが述べたように、あなたの目標は、単純に、"文字列が何バイトに格納されたかを取得する"です。
(そしてもちろん、バイトから文字列を再構築できるようにするために。)

それらの目的のために、私は正直にnotあなたがエンコーディングが必要であると人々があなたに言い続ける理由を理解していません。あなたは確かにこれについてエンコーディングを心配する必要はありません。

代わりにこれをしてください。

static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}

あなたのプログラム(あるいは他のプログラム)がどうにかして解釈するバイト数)をしようとしない限り、このアプローチにはnothingがあります。エンコーディングを心配することは、本当の理由であなたの人生をより複雑にするだけです。

このアプローチの追加の利点

それでも、データを取得して元の文字列を再構築できるので、文字列に無効な文字が含まれていても問題ありません。

あなたはbytesを見ているだけなので)同じようにエンコードされデコードされます。

ただし、特定のエンコーディングを使用した場合は、無効な文字のエンコード/デコードに問題が生じる可能性があります。

1793
Mehrdad

文字列のエンコーディングによって異なります( _ ascii _UTF-8 、...)。

例えば:

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

エンコーディングが重要な理由のごく一部です。

string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

ASCIIは単に特殊文字を処理するための設備が整っていません。

内部的には、.NETフレームワークは文字列を表すために UTF-16 を使用します。したがって、.NETが使用する正確なバイト数を取得するだけの場合は、System.Text.Encoding.Unicode.GetBytes (...)を使用します。

詳細については、.NET Frameworkの文字エンコーディング(MSDN)を参照してください。

1079
bmotmans

受け入れられた答えは非常に非常に複雑です。これには付属の.NETクラスを使用します。

const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

あなたがする必要がないならば、車輪を再発明しないでください...

267
BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());
110
Michael Buen

1文字は1 以上 bytes(最大約6)で表すことができるため、エンコードを考慮する必要があります。エンコードが異なると、これらのバイトの扱いが異なります。

Joelがこれについて投稿しています:

絶対的な最低限すべてのソフトウェア開発者は絶対に、確実にUnicodeと文字セットについて知っていなければならない(言い訳はしないでください!)

87

これはよくある質問です。質問作者が何を求めているのかを理解すること、そしてそれが最も一般的に必要とされるものとは異なることを理解することが重要です。それが必要とされないところでコードの誤用を防ぐために、私は最初に後で答えました。

共通のニーズ

すべての文字列には文字セットとエンコーディングがあります。 System.StringオブジェクトをSystem.Byteの配列に変換するとき、あなたはまだキャラクタセットとエンコーディングを持っています。 ほとんどの用途では、必要な文字セットとエンコーディングがわかっています。NETでは、「変換してコピーする」ことが簡単にできます。 適切なEncodingクラスを選ぶだけです。

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

変換は、ターゲット文字セットまたはエンコーディングがソース内の文字をサポートしない場合を処理する必要があるかもしれません。選択肢はいくつかあります。例外、置換、またはスキップです。デフォルトの方針は '?'に置き換えることです。

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

明らかに、変換は必ずしも無損失ではありません。

注:System.Stringの場合、ソース文字セットはUnicodeです。

唯一の紛らわしいことは、.NETが文字セットの名前をその文字セットの1つの特定のエンコーディングの名前に使用することです。 Encoding.UnicodeEncoding.UTF16と呼ばれるべきです。

ほとんどの用途でこれで終わりです。それがあなたが必要とするものならば、ここで読むのをやめてください。楽しみを見てください Joel Spolskyの記事 あなたがエンコーディングが何であるか理解できないならば。

特定のニーズ

さて、質問作者は、「すべての文字列はバイトの配列として格納されているのですか。そうしたバイトを単純に持つことができないのはなぜですか?」

彼は何の変換も望んでいません。

C#の仕様から

C#での文字および文字列処理はUnicodeエンコーディングを使用します。 char型はUTF-16コード単位を表し、文字列型は一連のUTF-16コード単位を表します。

したがって、null変換(つまり、UTF-16からUTF-16への変換)を要求した場合、目的の結果が得られることがわかります。

Encoding.Unicode.GetBytes(".NET String to byte array")

しかし、エンコーディングの言及を避けるためには、別の方法でやらなければなりません。中間データ型が受け入れられる場合、これに対する概念的な近道があります。

".NET String to byte array".ToCharArray()

それでは希望のデータ型にはなりませんが、 Mehrdad's answerBlockCopy を使用してこのChar配列をByte配列に変換する方法を示しています。ただし、これは文字列を2回コピーします。そして、それはまた明示的にエンコーディング特有のコードを使います:データ型System.Char

Stringが格納されている実際のバイト数に到達する唯一の方法は、ポインタを使用することです。 fixedステートメントは値のアドレスを取ることを可能にします。 C#の仕様から:

文字列型の式の場合、イニシャライザは文字列の最初の文字のアドレスを計算します。

そうするために、コンパイラーはRuntimeHelpers.OffsetToStringDataを使用してストリング・オブジェクトの他の部分をスキップするコードを作成します。そのため、生のバイトを取得するには、文字列へのポインタを作成し、必要なバイト数をコピーするだけです。

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 codeunits 
       and such codeunits are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

@CodesInChaosが指摘したように、結果はマシンのエンディアンに依存します。しかし、質問の作者はそれに関心がありません。

84
Tom Blodget

あなたの質問の最初の部分(バイトを取得する方法)はすでに他の人によって答えられています:System.Text.Encoding名前空間を見てください。

フォローアップの質問に答えます。なぜエンコードを選択する必要があるのですか?なぜ文字列クラス自体からそれを取得できないのですか?

答えは2つの部分に分かれています。

まず第一に、文字列クラスによって内部的に使用されるバイトは重要ではありません

プログラムが完全に.Netの世界にある場合は、ネットワーク経由でデータを送信している場合でも、文字列のバイト配列を取得する必要はまったくありません。代わりに、.Netシリアル化を使用して、データの送信を心配してください。実際のバイト数についてはもう心配しません。シリアル化フォーマッタがそれを行います。

一方、これらのバイトを.Netシリアル化ストリームからプルすることを保証できない場所に送信するとどうなりますか?この場合、明らかにこの外部システムが気にするので、エンコードを心配する必要があります。繰り返しますが、文字列で使用される内部バイトは重要ではありません。Netで内部的に使用される同じエンコーディングであっても、受信側でこのエンコーディングを明示できるようにエンコーディングを選択する必要があります。

この場合、バイトストリームを作成する作業をいくらか節約できるという考えの下で、可能であればメモリ内の文字列変数に格納された実際のバイトを使用することを好むかもしれないことを理解しています。ただし、出力を相手側で確実に理解し、mustであることを保証することと比較すると、重要ではありませんエンコーディングで明示的に。さらに、本当に内部バイトを一致させたい場合は、既にUnicodeエンコーディングを選択するだけで、パフォーマンスを節約できます。

2番目の部分に移動します... Unicodeエンコーディングisを選択して、.Netに基になるバイト。いくつかの新しいUnicode-Plusが出てきたとき、.Netランタイムはプログラムを壊さずにこの新しいより良いエンコーディングモデルを自由に使用する必要があるため、このエンコーディングを選択する必要があります。ただし、当面(および予見可能な将来)、Unicodeエンコードを選択するだけで、必要なものが得られます。

また、文字列をワイヤーに書き換える必要があることを理解することも重要です。これには、一致するエンコーディングを使用する場合でも、ビットパターンの少なくともいくつかの変換が含まれます。コンピューターはビッグエンディアンとリトルエンディアン、ネットワークバイトオーダー、パケット化、セッション情報などを考慮する必要があります。

43
Joel Coehoorn

Mehrdradの音 answer がうまくいくことを実証するためだけに、彼のアプローチは 対応のない代理文字 を永続させることさえできます。 System.Text.Encoding.UTF8.GetBytesSystem.Text.Encoding.Unicode.GetBytes;これらのエンコーディング方法では、例えば上位サロゲート文字d800を永続化することはできず、上位サロゲート文字を単に値fffdで置き換えるだけです。

using System;

class Program
{     
    static void Main(string[] args)
    {
        string t = "爱虫";            
        string s = "Test\ud800Test"; 

        byte[] dumpToBytes = GetBytes(s);
        string getItBack = GetString(dumpToBytes);

        foreach (char item in getItBack)
        {
            Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
        }    
    }

    static byte[] GetBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }

    static string GetString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }        
}

出力:

T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

System.Text.Encoding.UTF8.GetBytesまたはSystem.Text.Encoding.Unicode.GetBytesで試してみてください。それらは単に高いサロゲート文字を値fffdに置き換えます。

この質問に動きがあるたびに、ペアになっていないサロゲート文字を含んでいても文字列を永続化できるシリアライザ(マイクロソフト製またはサードパーティ製のコンポーネント)を考えています。私は時々これをグーグルします:シリアライゼーション不対代理文字.NET。これで私は眠りにつくことはありませんが、私の答えに不備があるとコメントしているときに不愉快な意見を言う人がいますが、それでも不対の代理文字に関しては同様に不備があります。

Microsoftは、BinaryFormatterSystem.Buffer.BlockCopyを使用したはずです。

谢谢!

43
Michael Buen

これを試してください、はるかに少ないコード:

System.Text.Encoding.UTF8.GetBytes("TEST String");
38
Nathan

ええと、私はすべての答えを読みましたが、それらはエンコーディングを使用することか、ペアになっていないサロゲートを削除するシリアライゼーションを使用することについてでした。

たとえば、文字列が SQL Server から来ていて、パスワードハッシュなどを格納しているバイト配列から作成されている場合、それは問題です。そこから何かを削除した場合、無効なハッシュが格納されます。XMLに格納したい場合は、そのままにしておく必要があります(XMLライタは、対応のないサロゲートに対して例外をドロップします)。

だから私はそのような場合にバイト配列の Base64 エンコーディングを使用しますが、ちょっと、インターネット上でこれに解決策が1つだけC#にあります、そしてそれにはバグがあり、一方向にしかありません。バグと書き戻しの手順。ここにいます、未来のグーグル:

public static byte[] StringToBytes(string str)
{
    byte[] data = new byte[str.Length * 2];
    for (int i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        data[i * 2] = (byte)(ch & 0xFF);
        data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
    }

    return data;
}

public static string StringFromBytes(byte[] arr)
{
    char[] ch = new char[arr.Length / 2];
    for (int i = 0; i < ch.Length; ++i)
    {
        ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
    }
    return new String(ch);
}
24
Gman

また、エンコードを考慮に入れる必要がある理由も説明してください。文字列が何バイトに格納されているのかを単純に取得することはできませんか?なぜエンコーディングに依存するのでしょうか。

「文字列のバイト数」のようなものがないからです。

文字列(より一般的にはテキスト)は、文字、数字、およびその他の記号の文字で構成されています。それで全部です。しかし、コンピュータは文字について何も知りません。それらはバイトしか処理できません。したがって、コンピュータを使用してテキストを保存または送信したい場合は、文字をバイトに変換する必要があります。どのようにそれをしますか?これがエンコーディングが登場する場所です。

エンコーディングは、論理文字を物理バイトに変換するための規約に過ぎません。最も簡単でよく知られているエンコーディングはASCIIです。英語で書いておけばそれだけで十分です。他の言語の場合は、より完全なエンコーディングが必要になります。今日では最も安全な選択肢の1つにUnicodeのフレーバーがあります。

つまり、「エンコーディングを使用せずに文字列のバイト数を取得する」のは、「言語を使用せずにテキストを書く」のと同じくらい不可能です。

ちなみに、私はこの知恵の小さな断片を読むことを強くお勧めします。 絶対に最低限すべてのソフトウェア開発者は絶対にUnicodeと文字セットについて知っていなければなりません(言い訳はしないでください)

21
Konamiman

stringbyte配列に変換するC#

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}
20

文字列とバイト配列間の変換には、次のコードを使用できます。

string s = "Hello World";

// String to Byte[]

byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);

// OR

byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);

// Byte[] to string

string str = System.Text.Encoding.UTF8.GetString(byte1);
16
Jarvis Stark
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}
15
gkrogers

よくわかりませんが、文字列はその情報をCharsの配列として格納していると考えられます。これはバイト数では非効率的です。具体的には、Charの定義は「Unicode文字を表します」です。

このサンプルを見てください。

String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info =  Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
    System.Console.WriteLine(enc.Name + " - " 
      + enc.GetEncoding().GetByteCount(str)
      + enc.GetEncoding().GetByteCount(str2));
}

Unicodeの回答はどちらの場合も14バイトですが、UTF-8の回答は最初の9バイト、2番目の7バイトです。

そのため、文字列で使用されるバイト数だけが必要な場合は、単にEncoding.Unicodeを使用します。ただし、記憶領域を使用すると効率が悪くなります。

12
Ed Marty

C#7.2でリリースされた Span<T> の出現により、文字列の基礎となるメモリ表現をマネージドバイト配列に取り込むための標準的な手法は次のとおりです。

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

それを元に戻すことは非スターターであるべきです。なぜならそれはあなたが実際に何らかの形でデータを解釈していることを意味します、しかし完全性のために:

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

NonPortableCastDangerousGetPinnableReferenceという名前は、おそらくこれを行うべきではないという主張をさらに推し進めるはずです。

Span<T>を扱うには System.Memory NuGetパッケージをインストールする必要があります

とにかく、 actual originalの質問とそれに続くコメントは、基礎となるメモリが「解釈」されていないことを意味しています。データを文字列として推論するのではなく、Streamクラスの実装を使用する必要があります。

11
John Rasch

重要な問題は、文字列内のグリフが32ビット(文字コードの場合は16ビット)を占めるが、1バイトには8ビットしかないことです。一対一のマッピングは、ASCIIの文字のみを含む文字列に自分自身を制限しない限り、存在しません。 System.Text.Encodingには、文字列をbyte []に​​マッピングする方法がたくさんあります。情報の損失を防ぎ、クライアントがbyte []を文字列にマッピングし直す必要があるときに、クライアントが使いやすいものを選ぶ必要があります。 。

Utf8は一般的なエンコーディングです。コンパクトで、損失が少ないわけではありません。

10
Hans Passant

つかいます:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

年です。結果:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103
8
mashet

手動で特定のエンコーディングを指定せずに.NET(C#)で文字列をbyte []に​​変換する方法を教えてください。

.NETの 文字列 は、テキストをUTF-16コード単位のシーケンスとして表しているため、バイトはすでにUTF-16のメモリにエンコードされています。

Mehrdad's Answer

Mehrdad's answer を使用できますが、文字はUTF-16であるため、実際にはエンコーディングを使用しています。 ToCharArrayを呼び出し、 ソース を見てchar[]を作成し、それにメモリを直接コピーします。次に、データを割り当てられているバイト配列にコピーします。そのため、内部では基礎となるバイトtwiceをコピーし、呼び出し後に使用されないchar配列を割り当てています。

トムブロジェットの答え

Tom Blodget's answer は、char配列を割り当ててそこにバイトをコピーする中間ステップをスキップするので、Mehrdadより20〜30%高速ですが、/unsafeオプションを使用してコンパイルする必要があります。あなたが絶対にエンコーディングを使いたくないのなら、私はこれが行くべき道だと思う。暗号化ログインをfixedブロック内に入れた場合は、別のバイト配列を割り当てて、そこにバイトをコピーする必要すらありません。

また、なぜエンコードを考慮に入れるべきなのでしょうか。文字列が何バイトに格納されているのかを単純に取得することはできませんか?文字エンコーディングに依存するのはなぜですか?

それがそれをする正しい方法だからです。 stringは抽象化です。

無効な文字を含む「文字列」がある場合、エンコーディングを使用すると問題が生じる可能性がありますが、それは起こらないはずです。あなたが無効な文字であなたの文字列にデータを入れているなら、あなたはそれを間違ってやっています。おそらく最初はバイト配列かBase64エンコーディングを使うべきでしょう。

System.Text.Encoding.Unicodeを使うと、あなたのコードはより弾力的になります。あなたのコードが実行されるシステムの エンディアン を心配する必要はありません。次のバージョンのCLRが別の内部文字エンコーディングを使用するかどうかを心配する必要はありません。

問題は、エンコーディングを心配したくない理由ではなく、無視して他のものを使用したい理由です。エンコーディングとは、文字列の抽象化を一連のバイトで表現することを意味します。 System.Text.Encoding.Unicodeはあなたにリトルエンディアンのバイトオーダーエンコーディングを与え、そして現在そして将来、すべてのシステムで同じことを実行します。

8
Jason Goemaat

最速の方法

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

_ edit _ Makotosanがコメントしたように、これが現在最善の方法です。

Encoding.UTF8.GetBytes(text)
8
Sunrising

OPの質問に最も近いアプローチはTom Blodgetのものです。これは実際にオブジェクトに入り、バイトを抽出します。これはStringオブジェクトの実装に依存するため、一番近いと言います。

"Can't I simply get what bytes the string has been stored in?"

確かに、それが問題の根本的な誤りが生じるところです。 Stringは興味深いデータ構造を持つことができるオブジェクトです。ペアになっていないサロゲートを保存することが可能になるので、それはすでにわかっています。それは長さを格納するかもしれません。それは素早いカウントを可能にする「ペアにされた」代理のそれぞれへのポインタを保つかもしれません。その他これらの余分なバイトはすべて文字データの一部ではありません。

必要なのは、配列内の各文字のバイト数です。そしてそれが 'encoding'が登場するところです。デフォルトではUTF-16LEが得られます。往復以外にバイト自体を気にしないのであれば、 'default'を含む任意のエンコーディングを選択して後で変換することができます(デフォルトのエンコーディング、コードポイント、バグ修正などの同じパラメータを想定)。ペアになっていないサロゲートなど、許可されているもの.

しかし、なぜ「エンコーディング」を魔法のままにしておくのでしょうか。どのバイトを取得するのかがわかるように、エンコードを指定しないでください。

"Why is there a dependency on character encodings?"

(この文脈では)エンコーディングは単にあなたの文字列を表すバイトを意味します。文字列オブジェクトのバイト数ではありません。あなたは文字列が格納されているバイト数を欲していました - これは質問が素朴に尋ねられるところです。文字列を表す連続した配列内の文字列のバイト数が必要でした。文字列オブジェクトに含まれる他のすべてのバイナリデータではありませんでした。

つまり、文字列の格納方法は関係ありません。文字列 "Encoded"をバイト配列のバイトにしたいとします。

Tom Bloget氏の回答が気に入っています。なぜなら、彼はあなたを '文字列オブジェクトのバイト'方向に導いたからです。それは実装に依存しますが、彼は内部を覗いているので、文字列のコピーを再構成するのは難しいかもしれません。

Mehrdadの回答は概念レベルで誤解を招くため、間違っています。あなたはまだエンコードされたバイトのリストを持っています。彼の特定の解決策は、対応のないサロゲートを保存することを可能にします - これは実装依存です。 GetBytesがデフォルトでUTF-8で文字列を返した場合、彼の特定の解決策は文字列のバイトを正確に生成しませんでした。


私はこれについて私の考えを変えました(Mehrdadの解決策) - これは文字列のバイト数を取得していません。文字列から作成された文字配列のバイト数を取得しています。エンコーディングに関係なく、c#のcharデータ型は固定サイズです。これにより、一貫性のある長さのバイト配列を生成でき、バイト配列のサイズに基づいて文字配列を再現できます。そのため、エンコーディングがUTF-8であっても、最大のutf8値に対応するために各charが6バイトであったとしても、それは機能します。つまり、文字のエンコーディングは関係ありません。

しかし、変換が使用されました - 各文字は固定サイズのボックス(c#の文字型)に配置されました。しかし、その表現が何であるかは問題ではなく、技術的にはOPの答えです。それで - もしあなたがとにかく変換​​するつもりなら...なぜ 'エンコード'しないのですか?

6
Gerard ONeill

次のコードを使用して、.NETのstringbyte arrayに変換できます。

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
6

これが私のStringからByte[]への変換の安全でない実装です。

public static unsafe Byte[] GetBytes(String s)
{
    Int32 length = s.Length * sizeof(Char);
    Byte[] bytes = new Byte[length];

    fixed (Char* pInput = s)
    fixed (Byte* pBytes = bytes)
    {
        Byte* source = (Byte*)pInput;
        Byte* destination = pBytes;

        if (length >= 16)
        {
            do
            {
                *((Int64*)destination) = *((Int64*)source);
                *((Int64*)(destination + 8)) = *((Int64*)(source + 8));

                source += 16;
                destination += 16;
            }
            while ((length -= 16) >= 16);
        }

        if (length > 0)
        {
            if ((length & 8) != 0)
            {
                *((Int64*)destination) = *((Int64*)source);

                source += 8;
                destination += 8;
            }

            if ((length & 4) != 0)
            {
                *((Int32*)destination) = *((Int32*)source);

                source += 4;
                destination += 4;
            }

            if ((length & 2) != 0)
            {
                *((Int16*)destination) = *((Int16*)source);

                source += 2;
                destination += 2;
            }

            if ((length & 1) != 0)
            {
                ++source;
                ++destination;

                destination[0] = source[0];
            }
        }
    }

    return bytes;
}

たとえそれほど洗練されていなくても、受け入れられている前の人よりはるかに速いです。これが私の10万回以上のストップウォッチベンチマークです。

[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms

[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms

[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms

それを使用するためには、あなたのプロジェクトビルドプロパティで "Allow Unsafe Code"をチェックしなければなりません。 .NET Framework 3.5と同様に、このメソッドはString拡張としても使用できます。

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}
4

あなたが本当に文字列の基になるバイトのコピーが欲しいなら、あなたは以下のもののような関数を使うことができます。 しかし、あなたはそうすべきではありません 原因を見つけるために読んでください。

[DllImport(
        "msvcrt.dll",
        EntryPoint = "memcpy",
        CallingConvention = CallingConvention.Cdecl,
        SetLastError = false)]
private static extern unsafe void* UnsafeMemoryCopy(
    void* destination,
    void* source,
    uint count);

public static byte[] GetUnderlyingBytes(string source)
{
    var length = source.Length * sizeof(char);
    var result = new byte[length];
    unsafe
    {
        fixed (char* firstSourceChar = source)
        fixed (byte* firstDestination = result)
        {
            var firstSource = (byte*)firstSourceChar;
            UnsafeMemoryCopy(
                firstDestination,
                firstSource,
                (uint)length);
        }
    }

    return result;
}

この関数はあなたの文字列の元になっているバイトのコピーをあなたに手に入れます。これらのバイトは、システム上でエンコードされている方法と同じ方法で取得できます。このエンコーディングはほぼ確実にUTF-16LEですが、これは実装の詳細なので気にする必要はありません。

それは より安全で、より単純で、より信頼性がある と呼ぶだけで/

System.Text.Encoding.Unicode.GetBytes()

たぶんこれは同じ結果を与えるでしょう、タイプするのはより簡単です、そしてバイトはへの呼び出しでいつも往復するでしょう

System.Text.Encoding.Unicode.GetString()
3
Jodrell

単にこれを使う:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
3
alireza amini

次の事実により、文字列はいくつかの異なる方法でバイト配列に変換できます。NETはUnicodeをサポートし、UnicodeはUTFと呼ばれるいくつかの異なるエンコードを標準化しています。バイト表現の長さは異なりますが、文字列をエンコードするときにその文字列にコーディングし直すことができるという意味では同等ですが、文字列を1つのUTFでエンコードし、異なるUTFの前提でデコードするとアップ。

また、.NETは非Unicodeエンコーディングをサポートしていますが、一般的な場合は無効です(ASCIIのように、Unicodeコードポイントの限定されたサブセットが実際の文字列で使用されている場合のみ有効です)。内部的には、.NETはUTF-16をサポートしていますが、ストリーム表現には通常UTF-8が使用されます。それはまたインターネットの標準デファクトです。

当然のことながら、文字列のバイト配列へのシリアライゼーションおよびデシリアライゼーションは抽象クラスであるクラスSystem.Text.Encodingによってサポートされています。その派生クラスは具象エンコーディングをサポートします:ASCIIEncodingと4つのUTF(System.Text.UnicodeEncodingはUTF-16をサポートします)

Ref このリンク。

System.Text.Encoding.GetBytesを使用してバイトの配列にシリアル化します。逆の操作にはSystem.Text.Encoding.GetCharsを使います。この関数は文字の配列を返すので、文字列を取得するには文字列コンストラクタSystem.String(char[])を使います。
このページを参照してください。

例:

string myString = //... some string

System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);

//next lines are written in response to a follow-up questions:

myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);

//how many times shall I repeat it to show there is a round-trip? :-)
2

それはあなたが望むバイト数によって異なります

これは、Tylerが非常に適切に言っているように 言った 「文字列は純粋なデータではありません。それらは 情報 も持っているからです。」この場合、情報は、文字列が作成されたときに想定されていたエンコーディングです。

文字列に(テキストではなく)バイナリデータが格納されていると仮定します。

これは彼自身の質問に対するOPのコメントに基づいており、ユースケースでのOPのヒントを理解すれば正しい質問です。

バイナリデータを文字列に格納することは、上記の想定されるエンコーディングのため、おそらく間違ったアプローチです。そのバイナリデータを(より適切であったはずのbyte[]配列ではなく)stringに格納したプログラムやライブラリがどんなものであっても、それが始まる前にすでに戦いを失っています。 REST要求/応答、またはmustで文字列を送信するものでユーザーにバイトを送信している場合、 Base64 が正しい方法です。

エンコードが不明なテキスト文字列がある場合

他のみんながこの間違った質問に間違って答えました。

文字列がそのままでよさそうな場合は、単にエンコーディング(できればUTFで始まるもの)を選び、対応するSystem.Text.Encoding.???.GetBytes()関数を使って、選択したエンコーディングにバイトを指定した人に伝えてください。

2
NH.

LINQを使った簡単なコード

string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

編集:下記のように、それは良い方法ではありません。

しかし、もっと適切なコーディングでLINQを理解するためにそれを使うことができます

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
2
Avlin

二通り:

public static byte[] StrToByteArray(this string s)
{
    List<byte> value = new List<byte>();
    foreach (char c in s.ToCharArray())
        value.Add(c.ToByte());
    return value.ToArray();
}

そして、

public static byte[] StrToByteArray(this string s)
{
    s = s.Replace(" ", string.Empty);
    byte[] buffer = new byte[s.Length / 2];
    for (int i = 0; i < s.Length; i += 2)
        buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
    return buffer;
}

私は一番上よりも一番下のほうをよく使う傾向がありますが、スピードのためにベンチマークしていません。

2
harmonik
bytes[] buffer = UnicodeEncoding.UTF8.GetBytes(string something); //for converting to UTF then get its bytes

bytes[] buffer = ASCIIEncoding.ASCII.GetBytes(string something); //for converting to ascii then get its bytes
2
user1120193

文字は、フォントテーブルへのルックアップキーでもあり、順序付け、大文字と小文字のバージョンなどの語彙的慣習でもあります。

したがって、文字はバイト(8ビット)ではなく、バイトは文字ではありません。特に、256バイトのバイトの並べ替えでは、一部の言語では数千シンボルに対応できません。したがって、文字を符号化するための様々な方法が考案されてきた。特定のクラスの言語をエンコードするもの(ASCIIエンコーディング)もあります。コードページを使用した複数言語(拡張ASCII)。あるいは、意欲的に、必要に応じて追加のバイトを選択的に含めることによるすべての言語、Unicode。

.NETフレームワークなどのシステム内では、Stringは特定の文字エンコーディングを意味します。 .NETでは、このエンコーディングはUnicodeです。フレームワークはデフォルトでUnicodeを読み書きするので、.NETでは文字エンコードの処理は通常必要ありません。

ただし、一般に、バイトストリームからシステムに文字列をロードするには、ソースのエンコーディングを知っている必要があります。したがって、それを正しく解釈して変換する必要があります。ちんぷんかんぷん)同様に、文字列が外部ソースに書き込まれると、特定のエンコーディングで書き込まれます。

0
George

byte[]からstringへ:

        return BitConverter.ToString(bytes);
0
Piero Alberto

文字列をbyte []に​​変換するには、次のソリューションを使用します。

string s = "abcdefghijklmnopqrstuvwxyz";
byte[] b = System.Text.UTF32Encoding.GetBytes(s);

役に立てば幸いです。

0

私は受け入れられた答えに似たVisual Basic拡張を書きましたが、変換に.NETメモリとマーシャリングを直接使用し、UnicodeEncoding.UTF8.GetStringUnicodeEncoding.UTF32.GetString、さらにはMemoryStream and BinaryFormatterのような他のメソッドではサポートされていない文字範囲をサポートします(????ChrW(55906)ChrW(55655)):

<Extension> _
Public Function ToBytesMarshal(ByRef str As String) As Byte()
    Dim gch As GCHandle = GCHandle.Alloc(str, GCHandleType.Pinned)
    Dim handle As IntPtr = gch.AddrOfPinnedObject
    ToBytesMarshal = New Byte(str.Length * 2 - 1) {}
    Try
        For i As Integer = 0 To ToBytesMarshal.Length - 1
            ToBytesMarshal.SetValue(Marshal.ReadByte(IntPtr.Add(handle, i)), i)
        Next
    Finally
        gch.Free()
    End Try
End Function

<Extension> _
Public Function ToStringMarshal(ByRef arr As Byte()) As String
    Dim gch As GCHandle = GCHandle.Alloc(arr, GCHandleType.Pinned)
    Try
        ToStringMarshal = Marshal.PtrToStringAuto(gch.AddrOfPinnedObject)
    Finally
        gch.Free()
    End Try
End Function
0