none
バイナリデータの指定したアドレスをTextboxに書き出す方法 RRS feed

  • 質問

  • 環境はVS2008 VBです。
    バイナリデータの指定したアドレスをTextboxに書き出す方法について教えてください。

    以下のようなプログラムを作っています。

    フォルダを選択

    Listboxに一覧を表示
    Listbox内ファイルを選択
    ↓ 「SelectedIndexChanged内イベント発生」
    バイナリを読み取りTextboxに表示

    の最後でつまずいています。
    読み取りたいバイナリのアドレスは"0"の一行のみです。
    アドレス"0"をTextboxに表示するにはどのようにしたらよいのでしょうか?

    説明下手ですがご存知の方、よろしくお願いします。

    2009年2月7日 7:58

回答

  • これだと、NullReferenceExceptionになりますよね。
    確かに、ReadBytesメソッドのサンプルではMemoryStreamクラスを使っているため、ファイルと結びつかないかもしれませんが、BinaryReaderクラスのページを漁っていくと、ファイルを使ったサンプルも出てきますよ。

    http://msdn.microsoft.com/ja-jp/library/system.io.binaryreader.aspx

    こういったページを見つけられなくとも、検索エンジンで「BinaryReader VB.NET サンプル」とか検索してみると良いかもしれませんね。


    あとは、ReadBytesメソッドはByte型の配列を返すので、それをGetStringに突っ込んで、得られたStringをTextBoxに表示するとかですかね。

    ただ、今のままだと、ShiftJISで解釈できないバイトが含まれていると、例外が出るか、そのバイトがなかったこととして扱われるかもしれません。
    その対策も考えてみて下さい。(EncoderReplacementFallbackやDecoderReplacementFallbackとか)


    参考になった返信には「回答としてマーク」のボタンを利用して、回答に設定しましょう(未解決の場合を除く)。
    • 回答としてマーク sk7474 2009年3月3日 9:17
    2009年2月13日 14:24
    モデレータ
  •  

    エラーの原因は、Dim testArray As Byte() = {0, 0, 0, 0}  では 4 バイト
    しか確保されてないからでしょう。(6 バイト必要)

    > 上記コードでもしバイナリ6バイトを読み取れたとして、Encoding.GetString
    > へはどのように渡すのでしょうか?

    GetString メソッドの引数に testArray を渡せば、その戻り値が文字列になり
    ます。Encoding は Azulean さんのレスにあったように、Shift_JIS として解釈
    できないバイトの取り扱いに要注意です。

    さらに、解釈できても表示できないバイト(例えば、0x00 とか改行など)をピ
    リオド '.' で表示したい場合は GetString する前に処置が必要です。

    ところで、前の質問に、

    > 画像通り、水色で囲った部分をTextboxに書き出したいです。

    とありましたが、「水色で囲った部分」は 16 バイトです。6 バイトでいいん
    ですか?

    • 回答としてマーク sk7474 2009年3月3日 9:16
    2009年2月14日 1:51
  • ニホンゴムズカシイ…。

    質問に単純に答えるなら、TextBox.Text = "0" ですが、やりたいことは違いますよね。
    Tanukichiさんの言う「バイナリ」とは何のことでしょうか?
    また「アドレス"0"」とは何のでしょうか? 一般に言われるアドレス"0"、つまりIntPtr.Zeroにはほぼ確実に期待するものは入っていません。
    更に「バイナリ」をどのように文字列化することを考えていますか?

    つまずいているのではなく、Tanikichiさんが「ご自身のやりたいこと・わからないこと」をわからないだけだと思います。
    実際、質問文を読み返してみてください。フォルダやファイルといったキーワードに触れられていますが、肝心の質問とは無関係に受け取れます。
    • 回答としてマーク sk7474 2009年3月3日 9:18
    2009年2月7日 11:42
  • こんばんは。

    最後の「バイナリを読み取りTextboxに表示」ができていないということですが、
    その前段には「Listbox内ファイルを選択」とあります。
    これは何かファイルを読み込んで、その内容の指定位置からデータを読み取り表示したい、
    ということでしょうか?

    もしそういうことでしたら、このファイル読込は上手くいっていますか?
    FileStreamクラスを使うと、指定位置から指定サイズでバイトデータを読み込むことが出来ます。
    ただ、質問の意図を読み違えたら申し訳ありません。

    あと、
    Tanukichi の発言:

    "バイナリエディタのアドレスが00000000の文字列(50 53 5A...などではなくPSZ...)をTextboxに表示したい"

    というのは、「アドレスが00000000の位置から」ということなんでしょうか。


    • 回答としてマーク sk7474 2009年3月3日 9:18
    2009年2月7日 14:30
  • Tanukichiさん の発言:

    FileStreamのサンプルがどこのサイトも完全に読み取る方法しかなく、自分には理解できないコードだったため使えませんでした。
    解説しているサイトもしくは簡素的でもいいのでサンプルをくださいませんか?

    例えば以下の記事はいかがでしょうか?

    バイナリ・ファイルを読み書きするには?[C#、VB]
    http://www.atmarkit.co.jp/fdotnet/dotnettips/669bincopy/bincopy.html




    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク sk7474 2009年3月3日 9:17
    2009年2月8日 0:43
    モデレータ
  •  

    「バイナリデータの指定したアドレス」とかいう表現なので話がややこし
    くなっているだけのように思えます。

    要するに、メモ帳などのテキストエディタで作ったテキストファイルの最
    初の一行を読んで TextBox に表示したいということだと思うのですが。

    そうであれば、エンコーディングが分かれば以下のようにして表示できる
    はずです。

     
    Using sr As New StreamReader(path, encoding)   
        TextBox1.Text = sr.ReadLine()   
    End Using   
     
     

    エンコーディングを取得する法は、以下のサイトが参考になると思います。

    文字コードを判別する
    http://dobon.net/vb/dotnet/string/detectcode.html


    なお、エンコーディングが不明でも、メモ帳で UTF-8, Unicode, Unicode
    Big Endian で作ったものであれば、以下のようにして表示できます。

     
    Using sr As New StreamReader(path)   
        TextBox1.Text = sr.ReadLine()   
    End Using   
     
     


    ANSI はダメです。日本語が文字化けします。

    • 回答としてマーク sk7474 2009年3月3日 9:17
    2009年2月8日 7:39
  • Tanukichi の発言:

    なんか説明が悪かったようです...

    すらっとまとめると
    "バイナリエディタのアドレスが00000000の文字列(50 53 5A...などではなくPSZ...)をTextboxに表示したい"
    ということです。

    ちょっと説明がほんとに下手なのですがよろしくお願いします。



    「50 53 5A などではなく、 PSZ」ということですが、まず、文字コードは何でしょう?最初の投稿には、「バイナリデータ」と書かれています。ここにある例、50 53 5A は、日本でよく使われる ANSI または Shift_JIS または EUC_JP または JIS では、PSZ となります。では、20 0A 08 07 というデータだったら、どう表示しましょうか?

    「読み取りたいバイナリのアドレスは、"0" の一行のみです」と言うことですがバイナリ データに「行」という概念はありません。何バイト表示すればよろしいでしょうか?

    「解説しているサイトもしくは簡素的でもいいのでサンプルをくださいませんか?」ということですが、何がしたいのかわからないので、示すことができません。何らかの文字コードで解釈したときに、可視文字のみで構成されているファイル(いわゆるテキスト ファイル)から表示したいのか(SurferOnWwwさんのコードをどうぞ)、不可視文字も含めたファイル(バイナリ ファイル)から可視文字のみ抜き出したいのか、解りません。

    テキスト ファイルの1行目をプレビューしたい、というのが真意のような気がするけど...


    Jitta@わんくま同盟
    • 回答としてマーク sk7474 2009年3月3日 9:17
    2009年2月9日 1:00

すべての返信

  • ニホンゴムズカシイ…。

    質問に単純に答えるなら、TextBox.Text = "0" ですが、やりたいことは違いますよね。
    Tanukichiさんの言う「バイナリ」とは何のことでしょうか?
    また「アドレス"0"」とは何のでしょうか? 一般に言われるアドレス"0"、つまりIntPtr.Zeroにはほぼ確実に期待するものは入っていません。
    更に「バイナリ」をどのように文字列化することを考えていますか?

    つまずいているのではなく、Tanikichiさんが「ご自身のやりたいこと・わからないこと」をわからないだけだと思います。
    実際、質問文を読み返してみてください。フォルダやファイルといったキーワードに触れられていますが、肝心の質問とは無関係に受け取れます。
    • 回答としてマーク sk7474 2009年3月3日 9:18
    2009年2月7日 11:42
  • なんか説明が悪かったようです...

    すらっとまとめると
    "バイナリエディタのアドレスが00000000の文字列(50 53 5A...などではなくPSZ...)をTextboxに表示したい"
    ということです。

    ちょっと説明がほんとに下手なのですがよろしくお願いします。
    2009年2月7日 12:24
  • こんばんは。

    最後の「バイナリを読み取りTextboxに表示」ができていないということですが、
    その前段には「Listbox内ファイルを選択」とあります。
    これは何かファイルを読み込んで、その内容の指定位置からデータを読み取り表示したい、
    ということでしょうか?

    もしそういうことでしたら、このファイル読込は上手くいっていますか?
    FileStreamクラスを使うと、指定位置から指定サイズでバイトデータを読み込むことが出来ます。
    ただ、質問の意図を読み違えたら申し訳ありません。

    あと、
    Tanukichi の発言:

    "バイナリエディタのアドレスが00000000の文字列(50 53 5A...などではなくPSZ...)をTextboxに表示したい"

    というのは、「アドレスが00000000の位置から」ということなんでしょうか。


    • 回答としてマーク sk7474 2009年3月3日 9:18
    2009年2月7日 14:30
  • ListBoxの内容を選択するとファイルパス(C:\a\a.txtなど)がtextbox1に挿入されているのでそこからファイルを指定してファイルを開こうと思っています。
    アドレスが00000000の文字列というのは要するに最初の一行目です。バイナリエディタのアドレスですが。

    FileStreamのサンプルがどこのサイトも完全に読み取る方法しかなく、自分には理解できないコードだったため使えませんでした。
    解説しているサイトもしくは簡素的でもいいのでサンプルをくださいませんか?
    よろしくお願いします。

    2009年2月7日 14:38
  • Tanukichi さん の発言:

    ListBoxの内容を選択するとファイルパス(C:\a\a.txtなど)がtextbox1に挿入されているのでそこからファイルを指定してファイルを開こうと思っています。
    アドレスが00000000の文字列というのは要するに最初の一行目です。バイナリエディタのアドレスですが。

    FileStreamのサンプルがどこのサイトも完全に読み取る方法しかなく、自分には理解できないコードだったため使えませんでした。
    解説しているサイトもしくは簡素的でもいいのでサンプルをくださいませんか?
    よろしくお願いします。



    先頭の位置から16バイト程度読み取れば良いのでは?
    大抵の場合、FileStreamで開いた状態では、先頭の位置にありますので、そこからByte配列で16個分、読めば良いのかもしれません。
    (明示的に先頭の位置に移動するというSeekをしておくのも手)

    そのByte配列をどうやって文字列にするかは、文字コード次第です。
    あなたが表示したいのはUTF-8なのか、ShiftJISなのか、UTF-16なのか、EUC-JPなのか、指定がありませんので、それについては何とも言えません。
    Encodingクラスとか使えばなんとかなるとは思いますが。

    ただ、文字として16個分読み取りたいのであれば、先の「Byte配列で16個決め打ちで読み込む」方針はまずいかもしれませんね。


    あとは本筋と離れた姿勢の話となりますが、今後のためにも記しておきます。

    「見つけた/提示されたサンプルが自分には理解できないので使えない」と言われると、何も提示できなくなります。
    「自分で理解できる」というのは、第三者から見ると量りようのない基準であり、それに沿った説明をしているページであると判断することや、回答者自らが説明を行うことは不可能です。
    「理解できないから使えない」ではなく、「理解するために教えて欲しい」ならまだ相談に乗ってもらえるかもしれません。


    参考になった返信には「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に指定できます)。
    2009年2月7日 16:46
    モデレータ
  • Tanukichiさん の発言:

    FileStreamのサンプルがどこのサイトも完全に読み取る方法しかなく、自分には理解できないコードだったため使えませんでした。
    解説しているサイトもしくは簡素的でもいいのでサンプルをくださいませんか?

    例えば以下の記事はいかがでしょうか?

    バイナリ・ファイルを読み書きするには?[C#、VB]
    http://www.atmarkit.co.jp/fdotnet/dotnettips/669bincopy/bincopy.html




    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク sk7474 2009年3月3日 9:17
    2009年2月8日 0:43
    モデレータ
  •  

    「バイナリデータの指定したアドレス」とかいう表現なので話がややこし
    くなっているだけのように思えます。

    要するに、メモ帳などのテキストエディタで作ったテキストファイルの最
    初の一行を読んで TextBox に表示したいということだと思うのですが。

    そうであれば、エンコーディングが分かれば以下のようにして表示できる
    はずです。

     
    Using sr As New StreamReader(path, encoding)   
        TextBox1.Text = sr.ReadLine()   
    End Using   
     
     

    エンコーディングを取得する法は、以下のサイトが参考になると思います。

    文字コードを判別する
    http://dobon.net/vb/dotnet/string/detectcode.html


    なお、エンコーディングが不明でも、メモ帳で UTF-8, Unicode, Unicode
    Big Endian で作ったものであれば、以下のようにして表示できます。

     
    Using sr As New StreamReader(path)   
        TextBox1.Text = sr.ReadLine()   
    End Using   
     
     


    ANSI はダメです。日本語が文字化けします。

    • 回答としてマーク sk7474 2009年3月3日 9:17
    2009年2月8日 7:39
  • Tanukichi の発言:

    なんか説明が悪かったようです...

    すらっとまとめると
    "バイナリエディタのアドレスが00000000の文字列(50 53 5A...などではなくPSZ...)をTextboxに表示したい"
    ということです。

    ちょっと説明がほんとに下手なのですがよろしくお願いします。



    「50 53 5A などではなく、 PSZ」ということですが、まず、文字コードは何でしょう?最初の投稿には、「バイナリデータ」と書かれています。ここにある例、50 53 5A は、日本でよく使われる ANSI または Shift_JIS または EUC_JP または JIS では、PSZ となります。では、20 0A 08 07 というデータだったら、どう表示しましょうか?

    「読み取りたいバイナリのアドレスは、"0" の一行のみです」と言うことですがバイナリ データに「行」という概念はありません。何バイト表示すればよろしいでしょうか?

    「解説しているサイトもしくは簡素的でもいいのでサンプルをくださいませんか?」ということですが、何がしたいのかわからないので、示すことができません。何らかの文字コードで解釈したときに、可視文字のみで構成されているファイル(いわゆるテキスト ファイル)から表示したいのか(SurferOnWwwさんのコードをどうぞ)、不可視文字も含めたファイル(バイナリ ファイル)から可視文字のみ抜き出したいのか、解りません。

    テキスト ファイルの1行目をプレビューしたい、というのが真意のような気がするけど...


    Jitta@わんくま同盟
    • 回答としてマーク sk7474 2009年3月3日 9:17
    2009年2月9日 1:00
  •  ANSI 、 Shift_JIS 、 EUC_JP でPSZ...の読み取りたい文章を読み取れました。
    読み取るのは特定の種類のファイルなので上記3つのどれかで読み取れればOKです。
    わかる方、ご教授をお願いします。

    >「見つけた/提示されたサンプルが自分には理解できないので使えない」と言われると、何も提示できなくなります。
    >「自分で理解できる」というのは、第三者から見ると量りようのない基準であり、それに沿った説明をしているページであると判断することや、回答者自らが説明を行うことは不可能です。
    >「理解できないから使えない」ではなく、「理解するために教えて欲しい」ならまだ相談に乗ってもらえるかもしれません。
    そうですね...自分の考え方が甘かったようです。反省します。
    2009年2月9日 7:31
  •  

    > わかる方、ご教授をお願いします。

    「わかる方」って、その言い方はあんまりだと思うんですが・・・

    Tanukichi さんが何をしたいのか分からないと回答者の皆さんが言っているの
    に無視ですか?

    2009年2月9日 14:28
  • このようなことをしたいです。
    http://imepita.jp/20090211/565800
    (バイナリエディタの画像)
    画像通り、水色で囲った部分をTextboxに書き出したいです。
    アドバイス、よろしくお願いします。

    2009年2月11日 6:53
  •  画像を見てみましたが、ファイルからByte型の配列にデータを格納し、格納された内容をテキストボックスに表示する。という理解でいいのでしょうか?

    2009年2月11日 14:44
  • Tanukichi さん の発言:

    アドバイス、よろしくお願いします。

    この「アドバイス」って何を求めているのでしょうか?
    使うクラスやメソッドだけを紹介すれば十分なのでしょうか?

    BinaryReader.ReadBytes(ファイルから読み取り)、Encoding.GetEncoding(ASCIIでかつ認識できないバイトを"."に置き換えるFallbackをセットしてEncodingインスタンスを取得)、Encoding.GetString(渡したbyte配列を文字列に変換)あたりを組み合わせればできるんだとは思います。
    参考になった返信には「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に指定できます)。
    • 回答としてマーク Tanukichi 2009年2月15日 11:15
    • 回答としてマークされていない Tanukichi 2009年2月15日 11:15
    2009年2月11日 15:03
    モデレータ
  • 回答ありがとうございます。 
    http://msdn.microsoft.com/ja-jp/library/system.io.binaryreader.readbytes.aspx
    を参考にしたのですが
    ”returnValue = instance.ReadBytes(count)”のどの部分で開くファイルを指定するか、取得した文字列(バイト?)をどこに出力するか
    がわからないのですが、今後のためにも教えていただけないでしょうか?
        Dim instance As System.IO.BinaryReader  
        Dim count As Integer = 6  
        Dim returnValue As Byte()  
        Dim Enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_JIS")  
     
        Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged  
     
            TextBox2.Text = (ListBox1.SelectedItem)  
     
    'この部分わからない
            returnValue = instance.ReadBytes(count)  
     End Sub
     
    自分でここまで作ってみたのですが違いありましたら指摘をお願いします。
    2009年2月13日 8:26
  • これだと、NullReferenceExceptionになりますよね。
    確かに、ReadBytesメソッドのサンプルではMemoryStreamクラスを使っているため、ファイルと結びつかないかもしれませんが、BinaryReaderクラスのページを漁っていくと、ファイルを使ったサンプルも出てきますよ。

    http://msdn.microsoft.com/ja-jp/library/system.io.binaryreader.aspx

    こういったページを見つけられなくとも、検索エンジンで「BinaryReader VB.NET サンプル」とか検索してみると良いかもしれませんね。


    あとは、ReadBytesメソッドはByte型の配列を返すので、それをGetStringに突っ込んで、得られたStringをTextBoxに表示するとかですかね。

    ただ、今のままだと、ShiftJISで解釈できないバイトが含まれていると、例外が出るか、そのバイトがなかったこととして扱われるかもしれません。
    その対策も考えてみて下さい。(EncoderReplacementFallbackやDecoderReplacementFallbackとか)


    参考になった返信には「回答としてマーク」のボタンを利用して、回答に設定しましょう(未解決の場合を除く)。
    • 回答としてマーク sk7474 2009年3月3日 9:17
    2009年2月13日 14:24
    モデレータ
  • 回答ありがとうございます
       
            'Const fileName As String  TextBox2.Text     
            Dim fileName As String = TextBox2.Text     
            On Error GoTo e     
            Dim binReader As New IO.BinaryReader( _     
                    File.Open(fileName, FileMode.Open))     
        
            Dim testArray As Byte() = {0, 0, 0, 0}     
            Dim count As Integer = binReader.Read(testArray, 0, 6)     
        
    e:      fi.Text = Err.Description     
        
     
    としたらfiというテキストボックスに
    配列のオフセットおよび長さが範囲を超えているか、カウンタがソース コレクションのインデックスから最後までの要素の数より大きい値です。
    が表示されました。
    このコードで自分がやりたいことは「Textbox2に表示されているパスを読み取り、そのファイルのバイナリ6バイトを取得する」をやっているつもりです。
    どこが間違っているか、どこを訂正したほうが教えていただけますでしょうか?

    あと、上記コードでもしバイナリ6バイトを読み取れたとして、Encoding.GetStringへはどのように渡すのでしょうか?
    よろしくお願いします。
    2009年2月14日 0:56
  •  

    エラーの原因は、Dim testArray As Byte() = {0, 0, 0, 0}  では 4 バイト
    しか確保されてないからでしょう。(6 バイト必要)

    > 上記コードでもしバイナリ6バイトを読み取れたとして、Encoding.GetString
    > へはどのように渡すのでしょうか?

    GetString メソッドの引数に testArray を渡せば、その戻り値が文字列になり
    ます。Encoding は Azulean さんのレスにあったように、Shift_JIS として解釈
    できないバイトの取り扱いに要注意です。

    さらに、解釈できても表示できないバイト(例えば、0x00 とか改行など)をピ
    リオド '.' で表示したい場合は GetString する前に処置が必要です。

    ところで、前の質問に、

    > 画像通り、水色で囲った部分をTextboxに書き出したいです。

    とありましたが、「水色で囲った部分」は 16 バイトです。6 バイトでいいん
    ですか?

    • 回答としてマーク sk7474 2009年3月3日 9:16
    2009年2月14日 1:51
  • Shift_JIS でいいのですか?ASCII 7ビットの範囲であれば、Shift_JIS、EUC_JP、JIS でも、コードは同じです。でも、8ビットコードになると、変わりますよ?

    それと、PSZ って、なんか、引っかかるのですが、ゲームか何かのセーブデータを逆アセンブルしようとしているのではないですよね?
    Jitta@わんくま同盟
    2009年2月14日 6:18
  • ありがとうございます!
    Textboxに書き出すことができました。
    しかし、"00"の部分があると"00"以降の文字列が書き出してくれません...
    (http://imepita.jp/20090215/447830)
    できれば、"00"の部分を半角スペースにしようと思い、
        Dim sp As New EncoderReplacementFallback(" ")  
        Dim df As New DecoderReplacementFallback(" ")  
        Dim Enc As Encoding = Encoding.GetEncoding("Shift_JIS", sp, df) 
    と書いてもダメ(PSZZとしか表示されない)
    testArray = Replace(testArray, "00"" "
    はエラーが出てビルドできずで自分ではもう思いつきません。
    どのようにすれば"00"以降を書き出せるのでしょうか?回答、よろしくお願いします

    >それと、PSZ って、なんか、引っかかるのですが、ゲームか何かのセーブデータを逆アセンブルしようとしているのではないですよね?
    違います。逆アセンブルなんて初心者の自分が知識など持っているはずがなく、興味もありません。
    2009年2月15日 3:33
  • 前のレスを読んで testArray のサイズを修正したでしょうか? 

    もう一度書きます。

    ところで、前の質問に、

    > 画像通り、水色で囲った部分をTextboxに書き出したいです。

    とありましたが、「水色で囲った部分」は 16 バイトです。6 バイトでいいん
    ですか?

    2009年2月15日 4:06
  •  はい。修正してあります。
    Dim testArray As Byte() = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}  
    Dim count As Integer = binReader.Read(testArray, 0, 16)  
    binReader.Close() 
    2009年2月15日 4:17
  •  

    Dim count As Integer = binReader.Read(testArray, 0, 16) で testArray に
    読み込んだ後、その中身がどうなっているかデバッガで見て調べてください。
    (デバッガで表示されるのは 10 進数で、バイナリエディタで表示されるのは
    16 進数なので注意)

    読めていれば表示できると思います。

    以下のコードで試してみたらどうなりますか? これで OK で、ファイルから
    読むと NG なら、うまくファイルを読み込めてないか、ファイルの中身が違う
    のだと思います。

    Dim testArray As Byte() = {&H50, &H53, &H5A, &H5A, &H0, &H0, _  
        &H0, &H0, &H4E, &H4E, &H4E, &H4E, _  
        &H4E, &H4E, &H0, &H0}  
    Dim sp As New EncoderReplacementFallback(" ")  
    Dim df As New DecoderReplacementFallback(" ")  
    Dim enc As EncodingEncoding = Encoding.GetEncoding("Shift_JIS", sp, df)  
    TextBox1.Text = enc.GetString(testArray)  
     
    2009年2月15日 12:05
  • ReplacementFallbackは変換できない文字を置き換えるという目的なので、今回のnull文字(他、制御文字を含む)については正常に変換できてしまうんですね。
    null文字は文字列の終端を意味する意図もあるので、それ以降の文字が表示されないといった現象として出てきています。

    これの対策をしようとすると、表示できる文字・表示できない文字を区別できないといけないんですが、どうしたもんかな。

    Encoding.ASCIIで変換した後に、Char.IsControlとか、Char.IsWhiteSpaceで制御文字と空白文字の判別はできそうだけども、ちょっと手間がかかりそうな感じがしますね。
    他に良い方法あるかなぁ。


    参考になった返信には「回答としてマーク」のボタンを利用して、回答に設定しましょう(未解決の場合を除く)。
    2009年2月15日 14:54
    モデレータ
  •  

    > null文字は文字列の終端を意味する意図もあるので、それ以降の文字が表示さ
    > れないといった現象として出てきています。

    コンソールアプリで試して PSZZ    NNNNNN と表示されたので、どれも同じだろ
    うと思っていたんですが・・・

    実際試してみるとそうではなくて、Windows アプリの TextBox では PSZZ でした。

    ちなみに、Web アプリの TextBox では PSZZNNNNNN(ソースを表示すると何故か
    value="PSZZ    NNNNNN  ")と、いずれも違う結果になりました。

    どうもゼロは終端文字を意味するというわけではなくて、表示結果がどうなるか
    は未定義ということではないのでしょうか?

    というわけで、以下のような感じで表示できないバイトを空白に置き換えないと
    ダメなようです。(あくまで「感じ」です。PSZZ    NNNNNN  は表示できるのは
    確認しましたが、それ以外のバイト列で十分に検証してないのでバグがあっ
    たらすみません)

            Dim testArray As Byte() = {&H50, &H53, &H5A, &H5A, &H0, &H0, _  
                &H0, &H0, &H4E, &H4E, &H4E, &H4E, _  
                &H4E, &H4E, &H0, &H0}  
            For i As Integer = 0 To testArray.Length - 1  
                ' 日本語の第2バイトか ASCII かは直前のバイトが 0x80 以上かどうかで判断。   
                If testArray(i) > &H7F Then  
                    i += 1  
                    Continue For  
                End If  
                If testArray(i) < &H20 OrElse testArray(i) > &H7E Then  
                    testArray(i) = &H20  
                End If  
            Next  
            Dim sp As New EncoderReplacementFallback(" ")  
            Dim df As New DecoderReplacementFallback(" ")  
            Dim enc As Encoding = Encoding.GetEncoding("Shift_JIS", sp, df)  
            TextBox1.Text = enc.GetString(testArray) 
    2009年2月16日 15:17
  • SurferOnWww さん の発言:

    > null文字は文字列の終端を意味する意図もあるので、それ以降の文字が表示さ
    > れないといった現象として出てきています。

    どうもゼロは終端文字を意味するというわけではなくて、表示結果がどうなるか
    は未定義ということではないのでしょうか?

    .NETの中での定義はされていないかもしれませんが、ホワイトスペース等が出力されると期待するのは危険です。

    SurferOnWww さん の発言:

            Dim testArray As Byte() = {&H50, &H53, &H5A, &H5A, &H0, &H0, _  
                &H0, &H0, &H4E, &H4E, &H4E, &H4E, _  
                &H4E, &H4E, &H0, &H0}  
            For i As Integer = 0 To testArray.Length - 1  
                ' 日本語の第2バイトか ASCII かは直前のバイトが 0x80 以上かどうかで判断。   
                If testArray(i) > &H7F Then  
                    i += 1  
                    Continue For  
                End If  
                If testArray(i) < &H20 OrElse testArray(i) > &H7E Then  
                    testArray(i) = &H20  
                End If  
            Next  
            Dim sp As New EncoderReplacementFallback(" ")  
            Dim df As New DecoderReplacementFallback(" ")  
            Dim enc As Encoding = Encoding.GetEncoding("Shift_JIS", sp, df)  
            TextBox1.Text = enc.GetString(testArray) 



    何をもって表示される・されないと判断するのが難しいとは思います。
    0x80以上であればShiftJISの2バイトコードの先頭バイトと判断するのもリスキーです。

    根拠: http://ja.wikipedia.org/wiki/Shift_JIS
    >Shift_JISの2バイトコードの空間は、第1バイトが0x81-9Fならびに0xE0-0xFC、第2バイトが0x40-0x7Eならびに0x80-0xFCである。


    参考になった返信には「回答としてマーク」のボタンを利用して、回答に設定しましょう(未解決の場合を除く)。
    2009年2月16日 16:12
    モデレータ
  •  

    > .NETの中での定義はされていないかもしれませんが、ホワイトスペース等
    > が出力されると期待するのは危険です。

    期待しているわけではないです。

    > 何をもって表示される・されないと判断するのが難しいとは思います。
    > 0x80以上であればShiftJISの2バイトコードの先頭バイトと判断するのもリスキーです。

    azulean さんのように、難しい判断を加えてリスクのないコードをアップしているつもりは
    ないです。

    2009年2月16日 16:57
  • Azulean の発言:

    何をもって表示される・されないと判断するのが難しいとは思います。
    0x80以上であればShiftJISの2バイトコードの先頭バイトと判断するのもリスキーです。

    それ以前に、質問者さんからは「Shift_JIS です」というアナウンスはありません。ASCII 7bit、EUC_JP、Shift_JIS、JIS のどれか、ということです。ということは、ASCII 7bit と仮定し、可視文字のみ扱うのが安全ではないでしょうか。
    Jitta@わんくま同盟
    2009年2月17日 3:15
  • こんにちは。中川俊輔です。

    皆様、詳細な回答ありがとうございます。

    Tanukichiさん、フォーラムのご利用ありがとうございます。
    勝手ながら、有用な情報と思われる回答へ回答マークをつけさせていただきました。

    今後ともフォーラムをよろしくお願いします。
    それでは!
    マイクロソフト株式会社 フォーラム オペレータ 中川 俊輔
    2009年3月3日 9:21