C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

No.85599 の関連記事表示

<< 0 >>
■85599  間違いを教えてください。
□投稿者/ 夜叉丸 -(2017/11/09(Thu) 16:57:18)

    分類:[.NET 全般] 


    byte[] valuearray;

    string strvalue = "";
    for (int isnum = 0; isnum < sstream.ToArray().Length; isnum++)
    strvalue += (char)valuearray [isnum];

    ↓↓↓↓↓
    逆変換したのですが

    byte[] valuearray = new byte[strvalue .Length];
    for (int inum = 0; inum < strvalue.Length; inum++)
    valuearray[inum] = (byte)strvalue[inum];

    元のデータと差異が生じています。
    どうしてでしょうか?
    どうすればよいのでしょうか?
親記事 /過去ログ146より / 関連記事表示
削除チェック/

■85600  Re[1]: 間違いを教えてください。
□投稿者/ 本醸造 -(2017/11/09(Thu) 18:11:29)
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85608  Re[1]: 間違いを教えてください。
□投稿者/ Jitta -(2017/11/09(Thu) 23:10:29)
    No85599 (夜叉丸 さん) に返信
    >
    > byte[] valuearray;
    >
    > string strvalue = "";
    > for (int isnum = 0; isnum < sstream.ToArray().Length; isnum++)
    > strvalue += (char)valuearray [isnum];
    >
    > ↓↓↓↓↓
    > 逆変換したのですが
    >
    > byte[] valuearray = new byte[strvalue .Length];
    > for (int inum = 0; inum < strvalue.Length; inum++)
    > valuearray[inum] = (byte)strvalue[inum];
    >
    > 元のデータと差異が生じています。
    > どうしてでしょうか?
    > どうすればよいのでしょうか?
    >

    ん?
    valuearray が20こ配列として、
    全部の値が0だったら、
    strvalueはどうなるんだ?
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85609  Re[1]: 間違いを教えてください。
□投稿者/ Azulean -(2017/11/09(Thu) 23:42:38)
    2017/11/09(Thu) 23:45:38 編集(投稿者)

    No85599 (夜叉丸 さん) に返信
    > string strvalue = "";
    > for (int isnum = 0; isnum < sstream.ToArray().Length; isnum++)
    > strvalue += (char)valuearray [isnum];

    なぜ、string に入れるのでしょうか。
    string は文字の集合であり、文字ではない byte 型を無理矢理変換して入れるようなものではありませんよ。
    byte の可変長配列が欲しいのなら、List<byte> の方が良いでしょう。

    // なお、char は 2 バイトです。

    > 逆変換したのですが

    元の strvalue そのままなのか、どこかを経由したのかは明らかにしておいた方が良いと思います。
    byte を無理矢理変換した string なので、経由した内容次第ではデータが化けることもあると予想されるため。

    > 元のデータと差異が生じています。
    > どうしてでしょうか?

    データが化けて、255 を超える値があるとか、0 を下回る値があるとか。
    あるいは、0 が終端文字と誤解されて途切れているとか。

    > どうすればよいのでしょうか?

    個人的に思うのは、string を使うのをやめるべきでしょうね。
    なぜこんな処理を書いているのか、目的・背景・理由を明らかにしてもらった方が良いでしょう。


    No85608 (Jitta さん) に返信
    > valuearray が20こ配列として、
    > 全部の値が0だったら、
    > strvalueはどうなるんだ?

    \0 が 20 個入った string になります。
    .NET の string はヌル文字終端ではなく、長さ管理なので。
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85610  Re[2]: 間違いを教えてください。
□投稿者/ 夜叉丸 -(2017/11/10(Fri) 08:28:03)
    文字列にして、INI ファイルに Key=Value の
    Value として登録するために
    関数を2つ作りました。
    
    byte[] の状態まではうまく変換できたのですが、
    String にすると変換できずにエラーメッセージが出てきたので
    byte[] → string か、byte[] → dynamic のどちらかで
    何かがおかしいのかと思ったのです。
    現状では Value に DataTable型 のデータを指定しています。
    
    
    private string DynamicToString(dynamic Value)
    {
    	// dynamic → byte[]
    	MemoryStream sstream = new MemoryStream();
    	IFormatter formatter = new BinaryFormatter();
    	formatter.Serialize(sstream, Value);
    
    	// byte[] → string
    	string strvalue = "";
    	for (int isnum = 0; isnum < sstream.ToArray().Length; isnum++) strvalue += (char)sstream.ToArray()[isnum];
    
    	return (strvalue);
    }
    
    private dynamic StringToDynamic(string Value)
    {
    	try
    	{
    		if (Value == "") return (null);
    
    		// string → byte[]
    		byte[] valuearray = new byte[Value.Length];
    		for (int inum = 0; inum < Value.Length; inum++) valuearray[inum] = (byte)Value[inum];
    
    		// byte[] → dynamic
    		MemoryStream dstream = new MemoryStream(valuearray);
    		IFormatter formatter = new BinaryFormatter();
    		return (formatter.Deserialize(dstream));
    	}
    	catch(Exception ex)
    	{
    		MessageBox.Show(ex.Message);
    		return (null);
    	}
    }
    
    
    
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85611  Re[3]: 間違いを教えてください。
□投稿者/ 夜叉丸 -(2017/11/10(Fri) 08:41:47)
    ちなみに表示されるエラーメッセージは以下のメッセージです。

    「バイナリストリーム'46'に、有効なBinaryHeaderが含まれていません。
    シリアル化と逆シリアル化の途中で、無効なストリームまたは
    オブジェクトのバージョン変更が発生した可能性があります。」

    また、今テスト的に変換しようとしているデータは以下のような文字列になっています。
    DataTable で 列は Start, End で 1行目に それぞれ "A1", "B1" を入れたものです。

    "\0\u0001\0\0\0&yuml;&yuml;&yuml;&yuml;\u0001\0\0\0\0\0\0\0\f\u0002\0\0\0NSystem.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\u0005\u0001\0\0\0\u0015System.Data.DataTable\u0003\0\0\0\u0019DataTable.RemotingVersion\tXmlSchema\vXmlDiffGram\u0003\u0001\u0001\u000eSystem.Version\u0002\0\0\0\t\u0003\0\0\0\u0006\u0004\0\0\0&Uacute;\u0005<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<xs:schema xmlns=\"\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n <xs:element name=\"Table1\">\r\n <xs:complexType>\r\n <xs:sequence>\r\n <xs:element name=\"START\" type=\"xs:string\" msdata:targetNamespace=\"\" minOccurs=\"0\" />\r\n <xs:element name=\"END\" type=\"xs:string\" msdata:targetNamespace=\"\" minOccurs=\"0\" />\r\n </xs:sequence>\r\n </xs:complexType>\r\n </xs:element>\r\n <xs:element name=\"tmpDataSet\" msdata:IsDataSet=\"true\" msdata:MainDataTable=\"Table1\" msdata:UseCurrentLocale=\"true\">\r\n <xs:complexType>\r\n <xs:choice minOccurs=\"0\" maxOccurs=\"unbounded\" />\r\n </xs:complexType>\r\n </xs:element>\r\n</xs:schema>\u0006\u0005\0\0\0&Atilde;\u0002<diffgr:diffgram xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\" xmlns:diffgr=\"urn:schemas-microsoft-com:xml-diffgram-v1\">\r\n <tmpDataSet>\r\n <Table1 diffgr:id=\"Table11\" msdata:rowOrder=\"0\" diffgr:hasChanges=\"inserted\">\r\n <START>A1</START>\r\n <END>B1</END>\r\n </Table1>\r\n </tmpDataSet>\r\n</diffgr:diffgram>\u0004\u0003\0\0\0\u000eSystem.Version\u0004\0\0\0\u0006_Major\u0006_Minor\u0006_Build\t_Revision\0\0\0\0\b\b\b\b\u0002\0\0\0\0\0\0\0&yuml;&yuml;&yuml;&yuml;&yuml;&yuml;&yuml;&yuml;\v"
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85612  Re[4]: 間違いを教えてください。
□投稿者/ 夜叉丸 -(2017/11/10(Fri) 08:57:20)
    なぜ、byte[] string の相互変換ができないのかがわからないので
    教えてください。

    ひょっとしたらたまたまかもしれませんけど
    List<string> や String などは普通に変換できましたし
    問題は起こりませんでした。
    今のところ DataTable だけがエラー発生します。


    逃げ道としては今のところ対応するために
    byte [A][B][C] → string '414243'
    として16進表示文字列にするしかないかと考えていますが、
    他にもっといい案があれば教えて下さい。
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85613  Re[5]: 間違いを教えてください。
□投稿者/ 夜叉丸 -(2017/11/10(Fri) 09:40:55)
    以下のように変更するととりあえずは動作するようになりましたが、
    文字サイズが2倍になっちゃいますし、
    入力されているデータの中身は全く分からくなりました。

    byte[] string は何が原因で使えないんでしょうか?


    string strvalue = "";
    for (int isnum = 0; isnum < sstream.ToArray().Length; isnum++) strvalue += ((char)sstream.ToArray()[isnum]).ToString();
    ↓↓↓↓↓
    string strvalue = "";
    for (int isnum = 0; isnum < sstream.ToArray().Length; isnum++) strvalue += (sstream.ToArray()[isnum]).ToString("X2");



    byte[] valuearray = new byte[Value.Length];
    for (int inum = 0; inum < Value.Length; inum++) valuearray[inum] = (byte)Value[inum];
    ↓↓↓↓↓
    int inum = 0;
    byte[] valuearray = new byte[Value.Length / 2];
    for (; inum < valuearray.Length; inum++) valuearray[inum] = (byte)Convert.ToInt32(Value.Substring(inum * 2, 2), 16);
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85616  Re[5]: 間違いを教えてください。
□投稿者/ 魔界の仮面弁士 -(2017/11/10(Fri) 12:04:11)
    2017/11/10(Fri) 12:06:01 編集(投稿者)

    No85612 (夜叉丸 さん) に返信
    > なぜ、byte[] string の相互変換ができないのかがわからないので
    > 教えてください。

    Azulean さんも書かれていますが、念のために確認。
    char/Char は「16 bit(2 バイト)長」のデータで、
    byte/Byte は「8 bit(1 バイト)長」のデータですが、
    その点の認識に差異はありますか?

    そして
     char a1 = 'a';
     char a1 = '\u0061';
     char a1 = (char)0x61;
     char a1 = (char)97;
    はいずれも同じ意味です。

    -----

    たとえば、まずこんなデータがあったとします。

    char a1 = '\u0061'; // Latin Small Letter A
    char a2 = '\u03B1'; // Greek Small Letter Alpha
    char a3 = '\uff41'; // Fullwidth Latin Small Letter A
    string str = new string(new char[] { a1, a2, a3 });


    データ内容が分かりやすくなるよう、上記は意図的に
    16 進数コードで表記していますが、要するに、
     string str = "aαa";
    を回りくどく書いているだけです。


    さて、上記の 3 文字(str 変数)を byte[] 配列にした場合、
    どのようなバイナリに変換されることを期待しておられますか?



    (1) UCS-2 あるいは UTF-16 バイナリ相当の 6 バイト
      61-00-B1-03-41-FF

    (2) UTF-16BE バイナリ相当の 6 バイト
      00-61-03-B1-FF-41

    (3) UTF-8 バイナリ相当の 6 バイト
      61-CE-B1-EF-BD-81

    (4) CP932 あるいは Shift_JIS バイナリ相当の 5 バイト
      61-83-BF-82-81

    (5) EUC-JP バイナリ相当の 5 バイト
      61-A6-C1-A3-E1

    (6) ISO-2022-JP バイナリ相当の 11 バイト
      61-1B-24-42-26-41-23-61-1B-28-42


    たとえば (1) を望むなら、
     string str = "aαa";
     byte[] bin = System.Text.Encoding.Unicode.GetBytes(str);
    で変換でき、それを復元するために
     string result = System.Text.Encoding.Unicode.GetString(bin);
    と書けます。
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85617  Re[3]: 間違いを教えてください。
□投稿者/ Azulean -(2017/11/10(Fri) 12:32:27)
    No85610 (夜叉丸 さん) に返信
    > 文字列にして、INI ファイルに Key=Value の
    > Value として登録するために
    > 関数を2つ作りました。

    BinaryFormatter でシリアライズした内容を ini ファイルに書き出すシナリオという理解で問題ないですか?

    BinaryFormatter の出力で得られる byte 配列をそのまま char 配列、そして string に変換すると、表示できない文字になる部分があります。
    たとえば、0 は扱う場所によっては文字列の終端とみなされます。
    ini ファイルを扱う API も 0 を終端とみなしますので途切れるでしょうね。
    その他、文字コードの都合で ini ファイルで扱えないバイトがあるので、ini に書き出すなら char にキャストするのではなく、何らかのエンコード(符号化)が必要です。
    16 進数にするのは1つの手ですし、BASE64 を使うのも選択肢になるかもしれません。(= が大丈夫かは不安ですが)

    なお、符号化によって、中身がパッとみてわからなくなる点は避けられません。ini ファイルを使う以上は仕方ないかと。
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85618  Re[4]: 間違いを教えてください。
□投稿者/ 魔界の仮面弁士 -(2017/11/10(Fri) 13:29:40)
    No85617 (Azulean さん) に返信
    > BASE64 を使うのも選択肢になるかもしれません。(= が大丈夫かは不安ですが)

    BASE64 の = が現われるのはパディング部だけなので、
    パディングが不要な実装、たとえば base64url が向いているかもしれません。
    https://ja.wikipedia.org/wiki/Base64


    // 保存したいバイナリ
    byte[] inBinary = { 0x96, 0xe9, 0x8d, 0xb3, 0x8a, 0xdb };

    // ini ファイルで保存可能な base64url 文字列に変換
    string iniString = inBinary.ToIniString();

    // 元のバイナリに復元
    byte[] outBinary = iniString.ToIniBinary();
     



    static class Base64Extensions
    {
     public static string ToIniString(this byte[] bin)
     {
      return Convert.ToBase64String(bin).TrimEnd('=')
       .Replace('/', '_').Replace('+', '-');
     }
     
     public static byte[] ToIniBinary(this string str)
     {
      int p = 4 - (str.Length % 4);
      string s = str;
      if (p != 4) { s += new string('=', p); }
      s = s.Replace('_', '/').Replace('-', '+');
      return Convert.FromBase64String(s);
     }
    }

    ini ファイルなら、+ → _ や / → - の置き換えは無くても大丈夫かも。
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85619  Re[5]: 間違いを教えてください。
□投稿者/ 夜叉丸 -(2017/11/10(Fri) 13:55:14)
    No85618 (魔界の仮面弁士 さん) に返信

    はっきりとは理解できていないのですが、
    char を介してコピーを行うと
    文字列としての特殊な処理がされるということでしょうか?

    何らかの方法にて byte[n] → string[n] のコピーは可能なのでしょうか?

記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85621  Re[6]: 間違いを教えてください。
□投稿者/ furu -(2017/11/10(Fri) 15:10:48)
    No85619 (夜叉丸 さん) に返信
    > ■No85618 (魔界の仮面弁士 さん) に返信
    >
    > 何らかの方法にて byte[n] → string[n] のコピーは可能なのでしょうか?
    >
    byte[n] →stringの間違い?

    byte(符号なし8ビット整数)からchar(16ビット数)へはコピー可能なので
    byte[n]からstringへのコピーは可能です。

    逆(string→byte[n])は
    各文字がU+0000 〜 U+00FFの範囲であるならば可能です。
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85620  Re[3]: 間違いを教えてください。
□投稿者/ とっちゃん -(2017/11/10(Fri) 15:02:57)
    No85619 (夜叉丸 さん) に返信

    > はっきりとは理解できていないのですが、
    > char を介してコピーを行うと
    > 文字列としての特殊な処理がされるということでしょうか?
    >
    .NET の char は、2バイトのデータ型です。
    C++ の wchar_t と同等で、データサイズは unsigned short と同じです。
    また、格納されているものは文字コードという前提で作られています。

    それと、string や、"..." は文字列型や文字列であって、文字配列ではありません。

    C や C++ は"..."は文字列と表記しますが実際は「\0で終わる文字の配列」という特殊な配列です。
    std::string のように文字列型を用いる場合でも、リテラルなデータは文字の配列であることに変わりはありません。

    ソースコードというテキストデータ上では同じ表現を用いていますが
    コンパイルされ、実行中のメモリの状態は異なる概念であることも注意が必要でしょう。



    > 何らかの方法にて byte[n] → string[n] のコピーは可能なのでしょうか?


    「n個の要素を持つバイトの配列」を 「n個の要素を持つ文字列の配列」にコピーするのですか?
    それとも
    「バイト配列のn番目の要素」を「stringのn番目の要素」としてコピーするのですか?

    どちらとも読めますが、これまでここについて明確にこうであるとは記述されていないように思います。
    (だからプログラムも怪しい)

    INIファイルにDataTableのレコード(あるいはデータブロックそのもの)を格納するのはどうなの?とも思いますが。。。

    自分の過去に携わってきたものとか、ここ30年余りのINIファイルの扱われ方などを考慮すると

    INI形式のファイルの特定のエントリーに、バイナリデータをバイナリチックな文字列として格納しておく
    という可能性が考えられます。

    構造としては... ■No85610 の DynamicToString の文字列化部分は

    // byte[] → string
    string strvalue = "";
    for (int isnum = 0; isnum < sstream.ToArray().Length; isnum++) strvalue += (char)sstream.ToArray()[isnum];

    ではなく、
    foreach( var ch in sstream.ToArray() ) strvalue += ch.ToString( "X2" );
    という感じが本来意図していた変換処理なのではないでしょうか?

    これだと byte[] の2倍になりますが30年くらい前のコードでもよく使われていた形式なので
    テキストデータで維持するのが目的になってるなら使うこともできると思います。

    個人的にはほかの人も書いているように BASE64 などの形式のほうがいいと思いますが
    互換性問題が出る気もするのでとりあえずは言及しないことにします。
記事No.85599 のレス /過去ログ146より / 関連記事表示
削除チェック/

■85623  Re[4]: 間違いを教えてください。
□投稿者/ 夜叉丸 -(2017/11/10(Fri) 16:40:46)
    ありがとうございました。

    逆変換が文字として処理されるためうまくいかないんですね。

    やはり、16進数に変換して文字列にします。
記事No.85599 のレス / END /過去ログ146より / 関連記事表示
削除チェック/



<< 0 >>

パスワード/

- Child Tree -