エンコーディングを手動で指定せずに、C#で文字列の一貫したバイト表現を取得するにはどうすればよいですか?


2190

どのようにして変換しないstringbyte[]手動で特定のエンコーディングを指定せずに、.NET(C#)で?

文字列を暗号化します。変換せずに暗号化することはできますが、ここでエンコードが機能する理由を知りたいのですが。

また、エンコードを考慮する必要があるのはなぜですか?文字列が格納されているバイトを簡単に取得できませんか?なぜ文字エンコーディングに依存しているのですか?


23
すべての文字列はバイトの配列として保存されますよね?単純にそれらのバイトを保持できないのはなぜですか?
Agnel Kurian、

135
エンコーディング、文字をバイトにマッピングするものです。たとえば、ASCIIでは、文字「A」は数値65にマップされます。別のエンコーディングでは、同じではない場合があります。.NETフレームワークで採用されている文字列への高レベルなアプローチでは、これはほとんど関係ありません(ただし、この場合を除きます)。
Lucas Jones、

20
悪魔の支持者を演じるには:メモリ内の文字列のバイトを取得し(.NETがそれらを使用するため)、なんらかの方法でそれらを操作したい場合(つまり、CRC32)、決して元の文字列にデコードして戻したくなかった場合...エンコーディングを気にする理由や、どのエンコーディングを使用するかを選択する方法は簡単ではありません。
グレッグ、

78
誰もまだこのリンクを提供していません。joelonsoftware.com
Bevan

28
charはバイトではなく、byteはcharではありません。charは、フォントテーブルのキーであり、語彙の伝統でもあります。文字列は文字のシーケンスです。(単語、段落、文、およびタイトルにも、独自の型定義を正当化する独自の字句の伝統があります-余談ですが)。整数、浮動小数点数、その他すべてのように、文字はバイトにエンコードされます。エンコーディングが1対1の単純なものだった時代がありました:ASCII。ただし、人間のすべての記号体系に対応するために、バイトの256順列は不十分であり、より多くのバイトを選択的に使用するようにエンコーディングが考案されました。
ジョージ14

回答:


1855

ここでの答えとは逆に、バイトを解釈する必要がない場合は、エンコードについて心配する必要はありません。

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

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

代わりにこれを実行してください:

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;
}

// Do NOT use on arbitrary bytes; only use on GetBytes's output on the SAME system
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);
}

あなたのプログラム(または他のプログラム)がバイトを何らかの方法で解釈しようとしない限り、あなたがそうするつもりであるとは明らかに言わなかったので、このアプローチには何の問題もありません!エンコーディングを心配すると、実際の理由もなく、生活が複雑になります。

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

それでもデータを取得して元の文字列を再構築できるため、文字列に無効な文字が含まれているかどうかは関係ありません。

バイトを表示しているだけなので、エンコードとデコードは同じです。

ただし、特定のエンコードを使用した場合、無効な文字のエンコード/デコードに問題が発生します。


247
何醜いことはこの1つは、約それGetStringGetBytes仕事を同じエンディアンを持つシステム上で実行する必要があります。したがって、これを使用して、他の場所で文字列に変換したいバイトを取得することはできません。そのため、これを使用したい状況を思い付くのに苦労しています。
CodesInChaos

72
@CodeInChaos:私が言ったように、これの全体的なポイントは、同じ種類のシステムで同じ機能のセットを使用したい場合です。そうでない場合は、使用しないでください。
user541686

193
-1(バイト対文字を理解していない)誰かが自分の文字列をバイト配列に変換することを望んでいることを保証します。例では、エンコードがIS関連します。
artbristol 2012年

401
@artbristol:回答(または他の回答...)を読むのが面倒にならない場合は、申し訳ありませんが、私と連絡を取るのにこれ以上の方法はありません。私は通常、他の人が私の答えで何をするのかを推測しようとするのではなく、OPに答えることを選びます-OPには知る権利があります。自分のために。あなたが同意しない場合でもそれは結構です。
user541686

185
この答えは非常に多くのレベルで間違っていますが、何よりもまず、「エンコーディングについて心配する必要がない!」というデクレレーションが原因です。GetBytesとGetStringの2つのメソッドは、Encoding.Unicode.GetBytes()とEncoding.Unicode.GetString()がすでに行っていることを単に再実装しただけなので、余分です。「プログラム(または他のプログラム)がバイトを解釈しようとしない限り」という文は、暗黙的にバイトがUnicodeとして解釈されるべきであることを意味するため、根本的に欠陥があります。
David

1108

文字列のエンコーディング(ASCIIUTF-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)の文字エンコーディングを参照してください。


14
しかし、なぜエンコードを考慮する必要があるのでしょうか。使用されているエンコーディングを確認せずに単純にバイトを取得できないのはなぜですか?必要な場合でも、Stringオブジェクト自体が使用されているエンコーディングを認識し、メモリにあるものを単にダンプする必要はありませんか?
Agnel Kurian、

57
.NET文字列は常にUnicodeとしてエンコードされます。したがって、System.Text.Encoding.Unicode.GetBytes();を使用します。.NETが文字を表すために使用するバイトのセットを取得します。しかし、なぜあなたはそれを望みますか?特にほとんどの文字が西部ラテンセットにある場合は、UTF-8をお勧めします。
AnthonyWJones 2009年

8
また、文字列で内部的に使用される正確なバイトは、それらを取得するシステムがそのエンコーディングを処理しないか、それを誤ったエンコーディングとして処理するかどうかには関係ありません。それがすべて.Net内にある場合、なぜバイトの配列に変換するのですか?それ以外の場合は、エンコードを明示することをお
勧め

11
@ Joel、System.Text.Encoding.Defaultは実行するマシンごとに異なる可能性があるので注意してください。そのため、常にUTF-8などのエンコーディングを指定することをお勧めします。
アッシュ

25
あなた(または他の誰か)がデータを一般的な「バイトのブロック」として扱うのではなく、実際にデータを解釈するつもりでない限り、エンコーディングは必要ありません。圧縮、暗号化などの場合、エンコーディングを気にする必要はありません。エンコーディングを気にせずにこれを行う方法については、私の回答を参照しください。(私はあなたがそうでないときにエンコーディングについて心配する必要があると言って-1を与えたかもしれません、しかし私は今日特に意地悪を感じていません。:P)
user541686

285

受け入れられた答えは非常に非常に複雑です。これには、含まれている.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);

必要がない場合は、ホイールを再発明しないでください...


14
承認された回答が変更された場合、記録のために、これはこの現在の日時におけるメルダッドの回答です。うまくいけば、OPはこれを再検討し、より良い解決策を受け入れるでしょう。
Thomas Eding 2013

7
原理的には良いですが、エンコーディングはSystem.Text.Encoding.UnicodeMehrdadの答えと同等でなければなりません。
Jodrell 2014年

5
質問は元の回答から何十億回も編集されているので、私の回答は少し古いかもしれません。Mehrdadの答えと同等の正確さを与えるつもりはなかったが、それを行うための賢明な方法を与えた。しかし、あなたは正しいかもしれません。ただし、元の質問の「文字列が格納されているバイトを取得する」というフレーズは非常に不正確です。保存、どこ?記憶に?ディスク上?メモリ内の場合、System.Text.Encoding.Unicode.GetBytesおそらくより正確になります。
Erik A. Brandstadmoen 2014年

7
@AMissico、あなたの提案はバグです。ただし、文字列がシステムのデフォルトのエンコーディング(システムのデフォルトのレガシー文字セットにASCII文字のみを含む文字列)と互換性があることが確実でない限り、しかし、OPはそれをどこにも述べていません。
フレデリック

5
@AMissicoこれにより、プログラムが異なるシステムで異なる結果をもたらす可能性があります。それは決して良いことではありません。それがハッシュや何かを作るためのものであっても(それがOPが 'encrypt'で意味するものだと思います)、同じ文字列は常に同じハッシュを与えるはずです。
Nyerguds

114
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());

2
これらすべての操作に同じBinaryFormatterインスタンスを使用できます
Joel Coehoorn、2009年

3
とても興味深い。どうやら、それはどんな高い代理Unicode文字も落とすでしょう。[BinaryFormatter ]のドキュメントを参照してください

95

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

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

すべてのソフトウェア開発者の絶対最小値は絶対に、確実にUnicodeと文字セットについて知っている必要があります(言い訳はありません!)


6
「1文字は1バイト以上で表すことができます」同意します。文字列のエンコーディングに関係なく、これらのバイトが必要なだけです。メモリに文字列を格納できる唯一の方法は、バイト単位です。文字も1バイト以上として格納されます。私はバイトを手に入れたいだけです。
Agnel Kurian、

16
あなた(または他の誰か)がデータを一般的な「バイトのブロック」として扱うのではなく、実際にデータを解釈するつもりでない限り、エンコーディングは必要ありません。圧縮、暗号化などの場合、エンコーディングを気にする必要はありません。エンコーディングを気にせずにこれを行う方法については、私の回答を参照しください。
user541686 2012

9
@Mehrdad-完全に、しかし私が最初に答えたときに述べたように、元の質問は、それらを変換した後、それらのバイトでどのようなOPが発生するかを警告しませんでした。Joelの回答で非常にうまくカバーされています。そして、回答の中で述べているように、.NETの世界に固執し、メソッドを使用して変換したり変換したりすると、満足です。その外に出るとすぐに、エンコーディングが重要になります。
Zhaph-Ben Duguid 2012

1つのコードポイントは、最大4バイトで表すことができます。(1つのUTF-32コード単位、UTF-16サロゲートペア、または4バイトのUTF-8。)UTF-8が4バイトより多くを必要とする値は、Unicodeの0x0..0x10FFFFの範囲外です。;-)
DevSolar 2018年

89

これはよくある質問です。質問者が何を求めているか、そして最も一般的なニーズである可能性が高いものとは異なることを理解することが重要です。不要なコードの誤用を防ぐために、最初に後者に回答しました。

共通のニーズ

すべての文字列には、文字セットとエンコーディングがあります。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.Unicode呼び出す必要がありますEncoding.UTF16

ほとんどの用途でそれで終わりです。それが必要な場合は、ここを読むのをやめてください。エンコーディングとは何かわからない場合は、楽しいJoel Spolskyの記事を参照してください。

特定のニーズ

さて、質問の作者は尋ねます、「すべての文字列はバイトの配列として保存されますよね?なぜそれらのバイトを単に持つことができないのですか?」

彼は改心を望んでいません。

C#の仕様

C#での文字と文字列の処理は、Unicodeエンコーディングを使用します。char型はUTF-16コード単位を表し、string型はUTF-16コード単位のシーケンスを表します。

したがって、ヌル変換(つまり、UTF-16からUTF-16への変換)を要求すると、望ましい結果が得られることがわかります。

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

しかし、エンコーディングの言及を避けるには、別の方法で行う必要があります。中間データ型が受け入れられる場合、これのための概念的なショートカットがあります:

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

これでは目的のデータ型は得られませんが、Mehrdadの答えは、BlockCopyを使用してこのChar配列をByte配列に変換する方法を示しています。ただし、これにより文字列が2回コピーされます。また、エンコーディング固有のコードであるdatatypeも明示的に使用していますSystem.Char

文字列が格納されている実際のバイトを取得する唯一の方法は、ポインタを使用することです。このfixedステートメントでは、値のアドレスを取得できます。C#仕様から:

[For]文字列型の式、...初期化子は、文字列の最初の文字のアドレスを計算します。

これを行うために、コンパイラはで文字列オブジェクトの他の部分をスキップするコードを記述し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が指摘したように、結果はマシンのエンディアンに依存します。しかし、質問の作者はそれを気にしていません。


3
@Janそれは正しいですが、文字列の長さはすでにコード単位の数を与えています(コードポイントではありません)。
Tom Blodget、2014

1
指摘してくれてありがとう!MSDNから:「Length[のString] プロパティは、Charこのインスタンスのオブジェクトの数を返します。Unicode文字の数ではありません。」したがって、サンプルコードは記述どおりに正しいものです。
Jan Hettich 2014

1
@supercat "char型はUTF-16コード単位を表し、string型は一連のUTF-16コード単位を表します。" —_ C#5仕様。new String(new []{'\uD800', '\u0030'})
Tom Blodget 2014年

1
@TomBlodget:つのインスタンスかかる場合興味深いことにGlobalization.SortKey、抽出物KeyDataにそれぞれから、およびパック結果のバイトをString[1文字ごとに2バイト、MSBが最初 ]、呼び出しString.CompareOrdinal結果の文字列の際は呼び出しよりも実質的に速くなるSortKey.Compareのインスタンス上でSortKey、またはmemcmpそれらのインスタンスを呼び出すことさえ。それを考えると、なぜKeyDataa Byte[]ではなくaを返すのStringでしょうか?
スーパーキャット2014年

1
悲しいかな、正しい答えですが、遅すぎるので、受け入れられたほど多くの票を獲得することはできません。TL; DRのせいで、人々は受け入れられた答えを揺るぎないものと考えるでしょう。copyenpastitと賛成票を投じます。
マーティンカポディッチ2015年

46

質問の最初の部分(バイトの取得方法)はすでに他の人から回答されていSystem.Text.Encodingます。名前空間を調べてください。

私はあなたのフォローアップ質問に取り組みます:なぜあなたはエンコーディングを選ぶ必要があるのですか?文字列クラス自体からそれを取得できないのはなぜですか?

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

まず第一に、文字列クラスによって内部的に使用されるバイトは重要ではありません、そして、あなたがそれらを仮定するときはいつでも、バグを導入している可能性があります。

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

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

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

これにより、2番目の部分に移動します... Unicodeエンコーディングを選択する、.Netが基になるバイトを使用するように指示されます。新しいエンコーディングのUnicode-Plusが出てきたとき、.Netランタイムは、プログラムを壊すことなく、この新しいより優れたエンコーディングモデルを自由に使用できる必要があるため、このエンコーディングを選択する必要があります。しかし、現時点では(そして近い将来)、Unicodeエンコーディングを選択するだけで、必要なものが得られます。

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


9
文字列のバイト配列を取得する必要がある.NETの領域があります。.NET暗号化クラスの多くには、バイト配列またはストリームを受け入れるComputeHash()などのメソッドが含まれています。最初に文字列をバイト配列に変換し(エンコーディングを選択)、オプションでそれをストリームにラップする以外に選択肢はありません。ただし、エンコーディング(UTF8など)を選択する限り、これに問題はありません。
Ash

44

ただ、Mehrdradのサウンドいることを実証するために、解答彼のアプローチをしても持続することができ、作品を不対サロゲート文字を例えば、多くの人が私の答えに対して水平にいたの(しかし、誰もが平等に有罪であるとSystem.Text.Encoding.UTF8.GetBytesSystem.Text.Encoding.Unicode.GetBytesこれらのエンコード方法は、上位サロゲートを持続することはできません。d800たとえば、文字、および単にサロゲート文字をvalueに置き換えるだけです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で置き換えます

この質問に動きがあるたびに、ペアリングされていないサロゲート文字が含まれている場合でも文字列を永続化できるシリアライザ(Microsoftまたはサードパーティコンポーネントからのもの)をまだ考えています。私は時々これをグーグルします:直列化の対になっていないサロゲート文字.NET。これによって睡眠が失われることはありませんが、私の回答に欠陥があるとコメントする人がときどきいるのはちょっと不快ですが、ペアになっていないサロゲートキャラクターに関しては、彼らの回答にも同じように欠陥があります。

くそー、マイクロソフトはSystem.Buffer.BlockCopyそのBinaryFormatterツで使用する必要があった

谢谢!


3
サロゲートは、有効なコードポイントを形成するためにペアで出現する必要はありませんか?その場合、データが破損する理由を理解できます。
dtanders

1
@dtandersはい、それは私の考えでもあります。ペアで表示する必要があります。意図的に文字列に入れてペアにしないと、ペアになっていないサロゲート文字が発生します。私が知らないのは、他の開発者がシリアル化アプローチ(私の答えは3年以上受け入れられた回答)がペアになっていないと見なしていないため、代わりにエンコーディングアウェアアプローチを使用する必要があると主張している理由です。代理文字はそのままです。しかし、彼らは自分たちのエンコード対応ソリューションが対になっていない代理文字も保持していないことを確認するのを忘れていました。皮肉なツイ
Michael Buen

System.Buffer.BlockCopy内部で使用するシリアライゼーションライブラリがある場合、すべてのエンコーディングアドボカシー関係者の議論は議論の余地があります
Michael Buen

2
@MichaelBuen主な問題は、あなたが大きなボールドの文字で何か問題ではないと言っているのではなく、問題ではないと言っていることです。その結果、あなたはあなたの答えを見て、将来他の人を苛立たせるような基本的なプログラミングの間違いをする人々を励ますでしょう。ペアになっていないサロゲートは文字列では無効です。これはchar配列ではないため、文字列を別の形式に変換すると、FFFDその文字でエラーが発生するのは当然です。手動で文字列を操作する場合は、推奨されるようにchar []を使用します。
2014

2
@dtanders:AはのSystem.String不変のシーケンスですChar。.NETは、元のStringオブジェクトにペアになっていないサロゲートが含まれている場合でも、オブジェクトを任意のオブジェクトから作成し、同じChar[]コンテンツをChar[]含むにエクスポートすることを常に許可していますChar[]
スーパーキャット2014年

41

次のコードを試してみてください。

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

次にこれを試してSystem.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép);、泣いてください!これは動作しますが、System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép").Length != System.Text.Encoding.UTF8.GetBytes("Arvizturo tukorfurogep").Lengthしばらく"Árvíztűrő tükörfúrógép".Length == "Arvizturo tukorfurogep".Length
mg30rg

9
@ mg30rg:なぜあなたの例は奇妙だと思いますか?可変幅エンコーディングでは、すべての文字が同じバイト長であるとは限りません。どうしたの?
ヴラド

@Vladただし、ここでより有効なコメントは、エンコードされたユニコードシンボルとして(つまり、バイトとして)、独自の発音記号を含む文字、発音記号が文字に追加された修飾子記号に分割されるのとは異なる結果を与えるということです。しかしiircには、一貫したバイト表現を取得できるように、.netにそれらを明確に分割するメソッドがあります。
Nyerguds

25

ええと、私はすべての回答を読みましたが、それらはエンコーディングの使用に関するものか、ペアになっていないサロゲートをドロップするシリアル化に関するものでした。

たとえば、文字列が、パスワードハッシュなどのバイト配列を格納するバイト配列から構築されたSQL Serverからのものである場合は、問題です。そこから何かを削除すると、無効なハッシュが格納され、XMLで保存したい場合はそのままにしておきます(XMLライターは、ペアになっていないサロゲートが検出すると例外をドロップするため)。

だから私はそのような場合にバイト配列のBase64エンコーディングを使用しますが、ねえ、インターネットではこれに対するC#での解決策は1つしかなく、それにはバグがあり、それは1つの方法に過ぎないため、バグを修正して書き戻しました手順。ここに、将来のグーグル:

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);
}

カスタムメソッドを使用してバイト配列をbase64に変換する代わりに、組み込みのコンバーターを使用するだけで済みます。Convert.ToBase64String(arr);
マコトサン

@誠さん、ありがとうございましたが、Convert.ToBase64String(arr); base64変換には使用しましたbyte[] (data) <-> string (serialized data to store in XML file)。しかし、イニシャルを取得するには、バイナリデータを含むbyte[] (data)を使用して何かを行う必要がありました(MSSQLがそれを返す方法です)。したがって、上記の関数はのためのものです。StringString (binary data) <-> byte[] (easy accessible binary data)
Gman、2012年

23

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

「文字列のバイト」なんてないから。

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

エンコーディングは、論理文字を物理バイトに変換するための規則にすぎません。最も単純で最もよく知られているエンコーディングはASCIIであり、英語で書く場合はそれで十分です。他の言語では、より完全なエンコーディングが必要になります。これは、Unicodeフレーバーのいずれかであるため、現在最も安全な選択肢です。

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

ちなみに、私はあなた(そして誰にとっても)のこの小さな知識を読むことを強くお勧めします:絶対最小値すべてのソフトウェア開発者絶対に、積極的にUnicodeと文字セットについて知っておく必要があります(言い訳はありません!)


2
明確にさせてください:「hello world」を物理バイトに変換するためにエンコーディングが使用されています。文字列は私のコンピューターに保存されているので、バイトで保存する必要があると確信しています。私は単にそれらのバイトにアクセスして、ディスクまたはその他の理由でそれらを保存したいだけです。これらのバイトを解釈したくありません。これらのバイトを解釈したくないので、この時点でのエンコーディングの必要性は、printfを呼び出すために電話回線を必要とするのと同じくらい見当違いです。
Agnel Kurian、

3
しかし、繰り返しになりますが、エンコーディングを使用しない限り、テキストから物理バイトへの変換という概念はありません。確かに、コンパイラーは何らかの方法でストリングをメモリーに保管しますが、これは内部エンコードを使用しているだけで、ユーザー(またはコンパイラー開発者以外の誰か)は知らないのです。したがって、何をする場合でも、文字列から物理バイトを取得するためのエンコーディングが必要です。
コナミマン

@Agnel Kurian:もちろん、文字列はそのコンテンツを格納するどこかにバイトの束を持っていることは事実です(UTF-16不公平)。しかし、アクセスできないようにする十分な理由があります。文字列は不変であり、内部のbyte []配列を取得できれば、それも変更できます。複数の文字列が同じデータを共有する場合があるため、これは不変性を破壊します。文字列を取得するためにUTF-16エンコーディングを使用すると、おそらくデータがコピーされます。
ollb '14年

2
@Gnafoo、バイトのコピーでできます。
Agnel Kurian、

22

stringaをbyte配列に変換するC#:

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

17
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}

しかし、なぜエンコードを考慮する必要があるのでしょうか。使用されているエンコーディングを確認せずに単純にバイトを取得できないのはなぜですか?必要な場合でも、Stringオブジェクト自体が使用されているエンコーディングを認識し、メモリにあるものを単にダンプする必要はありませんか?
Agnel Kurian、

5
これは常に機能するとは限りません。一部の特殊文字は、私が難しい方法で見つけたこのような方法を使用すると、迷子になる可能性があります。
JBキング

17

次のコードを使用して、文字列とバイト配列間の変換を行うことができます。

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);

VUPこれで問題が解決しました(byte [] ff = ASCIIEncoding.ASCII.GetBytes(barcodetxt.Text);)
r.hamd

16

Span<T>C#7.2 でリリースされたので、文字列の基礎となるメモリ表現をマネージバイト配列にキャプチャする正規の手法は次のとおりです。

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パッケージをインストールする必要があることに注意してください。

かかわらず、実際の元の質問とフォローアップのコメントは、基礎となるメモリを示し、(私は変更またはそのままそれを記述する必要を超えて読まれていない手段を想定している)「解釈」されていないことを意味するものではそのいくつかの実装Streamクラスデータを文字列としてまったく推論する代わりに使用する必要があります。


13

よくわかりませんが、文字列はその情報を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、ストレージスペースが非効率的です。


10

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

Utf8は人気のあるエンコーディングであり、コンパクトで損失がありません。


3
UTF-8は、大部分の文字が英語(ASCII)文字セットである場合にのみコンパクトです。中国語の文字列が長い場合、UTF-16はその文字列のUTF-8よりもコンパクトなエンコーディングになります。これは、UTF-8が1バイトを使用してASCIIをエンコードし、それ以外の場合は3(または4)を使用するためです。
Joel Mueller、

7
本当です。しかし、中国語のテキストの扱いに精通している場合、エンコーディングについてどうしたらわかりませんか?
ハンスパッサント

9

使用する:

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

結果は次のとおりです。

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

OPは特にエンコーディングを指定しないように要求します...「特定のエンコーディングを手動で指定せずに」
Ferdz

8

最速の方法

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

マコトサンがコメントしたように編集することは、これが今や最善の方法です:

Encoding.UTF8.GetBytes(text)

8
ASCIIEncoding .....は必要ありません。単にEncoding.UTF8.GetBytes(text)を使用することをお勧めします。
マコトサン

8

特定のエンコーディングを手動で指定せずに、.NET(C#)で文字列をbyte []に​​変換するにはどうすればよいですか?

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

Mehrdadの回答

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

トム・ブロジェットの答え

Tom Blodgetの回答はMehrdadよりも20〜30%高速です。これは、char配列を割り当ててそこにバイトをコピーする中間ステップをスキップするためですが、/unsafeオプションを指定してコンパイルする必要があります。どうしてもエンコーディングを使いたくないのなら、これでいいと思います。暗号化ログインをfixedブロック内に配置する場合、別のバイト配列を割り当てて、そこにバイトをコピーする必要さえありません。

また、エンコードを考慮する必要があるのはなぜですか?文字列が格納されているバイトを簡単に取得できませんか?なぜ文字エンコーディングに依存しているのですか?

それが適切な方法だからです。 string抽象化です。

エンコーディングを使用すると、無効な文字を含む「文字列」がある場合に問題が発生する可能性がありますが、これは起こりません。無効な文字を含む文字列にデータを取得している場合、それは間違っています。最初に、バイト配列またはBase64エンコーディングを使用しているはずです。

を使用するSystem.Text.Encoding.Unicodeと、コードの耐障害性が向上します。コードが実行されるシステムのエンディアンについて心配する必要はありません。CLRの次のバージョンが別の内部文字エンコードを使用するかどうかを心配する必要はありません。

問題は、なぜエンコーディングを心配したいのかではなく、なぜそれを無視して別のものを使用したいのかだと思います。エンコーディングは、文字列の抽象化を一連のバイトで表すことを目的としています。 System.Text.Encoding.Unicodeリトルエンディアンのバイトオーダーエンコーディングを提供し、現在および将来のすべてのシステムで同じように実行します。


実際、C#の文字列はUTF-16だけに制限されていません。事実は、16ビットのコード単位のベクトルが含まれていることですが、これらの16ビットのコード単位は、有効なUTF-16に制限されていません。ただし、16ビットであるため、8ビットに変換するにはエンコード(バイト順)が必要です。文字列は、バイナリコード(ビットマップイメージなど)を含む非Unicodeデータを格納できます。このような解釈を行うI / Oおよびテキストフォーマッタでのみ、UTF-16として解釈されます。
verdy_p

そのため、C#文字列では、0xFFFFや0xFFFEなどのコードユニットをUTF-16の非文字であっても安全に格納でき、0xDC00..0xDFFFにコードユニットが後に続かない分離された0xD800を格納できます(つまりUTF-16では無効なペアになっていないサロゲート)。Javascript / ECMAscriptおよびJavaの文字列にも同じことが当てはまります。
verdy_p

"GetBytes"を使用するときは、もちろんエンコーディングを指定しませんが、文字列にローカルに格納されている各コードユニットの特定の2バイトを取得するためにバイトオーダーを想定します。バイトから新しい文字列を作成するときは、コンバータも必要です。必ずしもUTF-8からUTF-16に変換する必要はありません。上位バイトに余分な0を挿入するか、2バイトをパックします(MSBファーストまたはLSBファースト順)。同じ16ビットコード単位。文字列は、16ビット整数の配列のコンパクトな形式です。「文字」との関係は別の問題です。C#では文字列として表されるため、実際の型ではありません
verdy_p

7

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

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

もちろん、それが問題の根本的なエラーが発生する場所です。文字列は、興味深いデータ構造を持つオブジェクトです。ペアリングされていないサロゲートを保存できるため、すでにわかっています。長さを保存する場合があります。それは、迅速なカウントを可能にする「ペアにされた」代理のそれぞれへのポインタを保持するかもしれません。等これらの余分なバイトはすべて文字データの一部ではありません。

必要なのは、配列内の各文字のバイトです。そして、それが「エンコーディング」の出番です。デフォルトでは、UTF-16LEを取得します。往復以外のバイト自体を気にしない場合は、「デフォルト」を含む任意のエンコーディングを選択し、後で変換し直すことができます(デフォルトのエンコーディングと同じパラメータ、コードポイント、バグ修正などを想定) 、許可されていない代理母などの許可されたもの

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

"Why is there a dependency on character encodings?"

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

つまり、文字列がどのように格納されるかは関係ありません。文字列をバイト配列のバイトに「エンコード」したい。

トム・ブログの答えが気に入ったのは、彼が「文字列オブジェクトのバイト数」の方向に連れて行ったからです。それは実装に依存しますが、彼は内部を覗いているので、文字列のコピーを再構成するのは難しいかもしれません。

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


私はこれについて変更しました(Mehrdadのソリューション)-これは文字列のバイトを取得していません。むしろ、文字列から作成された文字配列のバイトを取得しています。エンコードに関係なく、c#のcharデータ型は固定サイズです。これにより、一貫した長さのバイト配列を生成でき、バイト配列のサイズに基づいて文字配列を再現できます。したがって、エンコードがUTF-8であるが、各文字が最大のutf8値に対応するために6バイトであった場合でも、それは機能します。実際、文字のエンコーディングは重要ではありません。

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


これらの文字はされているサポートされていない exapmleためUTF-8またはUTF-16、あるいはUTF-32で:񩱠(Char) 55906(Char) 55655。したがって、あなたは間違っている可能性があり、Mehrdadの答えは、使用されているエンコーディングのタイプを考慮せずに安全な変換です。
Mojtaba Rezaeian 2016

レイモン、文字はすでにいくつかのユニコード値で表されています-すべてのユニコード値はすべてのutfで表すことができます。あなたが話していることについてのより長い説明はありますか?これらの2つの値(または3 ..)にはどの文字エンコーディングが存在しますか?
Gerard ONeill、2016

これらは無効な文字であり、どのエンコード範囲でもサポートされていません。これは、100%役に立たないという意味ではありません。エンコーディングに関係なく、任意のタイプの文字列を同等のバイト配列に変換するコードは、まったく間違った解決策ではなく、必要に応じて独自の使用法があります。
Mojtaba Rezaeian 2016

1
では、問題を理解していないと思います。私たちはそれがユニコード準拠の配列であることを知っています-実際、それは.netなので、それはUTF-16であることを知っています。したがって、それらのキャラクターはそこには存在しません。また、内部表現の変更に関する私のコメントを完全には読んでいません。文字列はオブジェクトであり、エンコードされたバイト配列ではありません。だから私はあなたの最後の声明に同意しません。すべてのUnicode文字列を任意のUTFエンコーディングに変換するコードが必要です。これはあなたが望むことを正しく行います。
Gerard ONeill、2016

オブジェクトは、元々現在の状態にあるオブジェクトを表すビットのシーケンスであるデータのシーケンスです。したがって、メモリ内のオブジェクトの状態を維持する必要がある場合があるため、プログラミング言語のすべてのデータはバイトの配列(各バイトで8ビットを定義)に変換できます。バイトシーケンスをファイルまたはメモリに保存して保持し、ディスクから読み取った後、整数、bigint、画像、ASCII文字列、UTF-8文字列、暗号化文字列、または独自に定義したデータ型としてキャストできます。したがって、オブジェクトがバイトシーケンスとは異なるものであるとは言えません。
Mojtaba Rezaeian 2016

6

あなたは.NETでa stringをa byte arrayに変換するために次のコードを使うことができます

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

3

文字列の基礎となるバイトのコピーが本当に必要な場合は、次のような関数を使用できます。ただし、その理由を理解するために読み進めないでください。

[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

ここでの私の危険な実装であるStringByte[]の変換は:

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;
}

エレガントではないにしても、受け入れられているanwserのものよりもはるかに高速です。以下は、10000000回の反復でのストップウォッチベンチマークです。

[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

これを使用するには、プロジェクトのビルドプロパティで「安全でないコードを許可する」にチェックマークを付ける必要があります。.NET Framework 3.5に従って、このメソッドは文字列拡張としても使用できます。

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

RuntimeHelpers.OffsetToStringDataItaniumバージョンの.NET の値は8の倍数ですか?それ以外の場合は、アラインされていない読み取りが原因で失敗します。
Jon Hanna

呼び出す方が簡単ではないでしょうmemcpyか?stackoverflow.com/a/27124232/659190
Jodrell

2

単にこれを使用してください:

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

2
...そして127以上のジャンプコピーですべての文字を失います。私の母国語では、「Árvíztűrőtükörfúrógép。」と書くことは完全に有効です。取得できない失われた情報をSystem.Text.ASCIIEncoding.Default.GetBytes("Árvíztűrő tükörfúrógép.").ToString();返し"Árvizturo tukörfurogép."ます。(すべての文字が
失われる

2

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

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

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

このリンクを参照してください。

を使用してバイトの配列にシリアル化する場合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

それはあなたがバイトをしたいものに依存します

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

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

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

バイナリデータを文字列に格納することは、上記の想定されたエンコーディングのため、おそらく間違ったアプローチです!プログラムやライブラリがそのバイナリデータをstringbyte[]より適切な配列ではなく)に格納したものは、戦闘が始まる前にすでに負けています。RESTリクエスト/レスポンス、または文字列を送信する必要のあるものでバイトを送信している場合は、Base64が適切なアプローチです。

不明なエンコーディングのテキスト文字列がある場合

他の誰もがこの誤った質問に誤って答えた。

文字列がそのままのように見える場合は、エンコーディング(できればUTFで始まるもの)を選択し、対応するSystem.Text.Encoding.???.GetBytes()関数を使用して、選択したエンコーディングにバイトを与える人に通知します。


2

バイトをどうするつもりなのか尋ねられたら、あなたは答えました

暗号化します。変換せずに暗号化できますが、ここでエンコーディングが機能する理由を知りたいのですが。ちょうど私に言うバイトは私が言うことです。

この暗号化されたデータをネットワーク経由で送信するのか、後でメモリにロードするのか、または別のプロセスにスチームするのかに関係なく、ある時点でデータを解読するつもりであることは明らかです。その場合の答えは、通信プロトコルを定義しているということです。通信プロトコルは、プログラミング言語とそれに関連するランタイムの実装の詳細に関して定義すべきではありません。これにはいくつかの理由があります。

  • 異なる言語またはランタイムで実装されたプロセスと通信する必要がある場合があります。(これには、たとえば、別のマシンで実行されているサーバーや、JavaScriptブラウザークライアントに文字列を送信することが含まれる場合があります。)
  • プログラムは、将来、別の言語またはランタイムで再実装される可能性があります。
  • .NET実装は、文字列の内部表現を変更する可能性があります。これは遠く聞こえたように思えるかもしれませんが、これは実際にはメモリ使用量を減らすためにJava 9で起こりました。.NETが追随できなかった理由はありません。スキートは、UTF-16が今日最適ではない可能性があること示唆しており、絵文字や、表現に2バイト以上を必要とするUnicodeの他のブロックが出現し、将来、内部表現が変更される可能性が高まります。

通信する場合(完全に異なるプロセスまたは将来同じプログラムと通信する場合)、プロトコルを厳密に定義して、プロトコルを操作したり、誤ってバグを作成したりする難しさを最小限に抑える必要があります。.NETの内部表現によっては、厳密で明確ではなく、一貫した定義であることが保証されていません。標準エンコーディング、将来的に失敗することのない厳密な定義です。

つまり、エンコーディングを指定せずに整合性の要件を満たすことはできません。

あなたは可能確かに .NETが内部またはその他の理由のためにそれを使用しますが、明示的にエンコードすることを選択して、あなたのコード内で明示的にそれらの変換を実行する必要がなく、依存するので、あなたが有意に良好あなたのプロセスを実行することを発見した場合、直接UTF-16を使用することを選択します.NETの内部実装。

したがって、エンコーディングを選択して使用します。

using System.Text;

// ...

Encoding.Unicode.GetBytes("abc"); # UTF-16 little endian
Encoding.UTF8.GetBytes("abc")

ご覧のとおり、組み込みのエンコーディングオブジェクトを使用する方が、独自のリーダー/ライターメソッドを実装するよりも実際にはコードが少なくなっています。


1

二通り:

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;
}

私は一番下よりも一番下を使用する傾向がありますが、速度についてはベンチマークしていません。


4
マルチバイト文字はどうですか?
Agnel Kurian

c.ToByte()はプライベートです:S
Khodor

@AgnelKurian Msdnは、 「このメソッドは、渡されたCharオブジェクトの数値コードを表す符号なしバイト値を返します
mg30rg 2018年

1
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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.