CSVファイルで次の列に移動させたい

タグの編集
投稿者 ポン吉  (高校生) 投稿日時 2015/11/2 18:01:53
私は今、CSVファイルを使ってクイズを作成しています。
表示の仕方は以下の通りです
問題文,選択肢1,選択肢2,選択肢3,正答
ああああ,いいいい,うううう,ええええ,いいいい
ですが、最初の一列しか表示できず困っています
お願いします!私に2列目に移動できるコードを教えてください!
コードはこちらのサイトのものを使用させていただきました
 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Reader As New IO.StreamReader("作品の問題点.csv", System.Text.Encoding.GetEncoding("Shift-JIS"))
        Dim Items() As String                'CSVの各項目を表す配列
        Dim Line As String = Reader.ReadToEnd 'CSVの一行
        Dim PostalCode As String            
        Button1.Visible = False
        Button2.Visible = True
        Button3.Visible = True
        Do Until IsNothing(Line)

            Items = Line.Split(",")                   
            PostalCode = Items(0)                    
            Label1.Text = Items(0)
            Button2.Text = Items(1)
            Button3.Text = Items(3)
            Line = Reader.ReadLine                  '次の行を読み込む。

        Loop
        Reader.Close()
    End Sub
投稿者 ななしん  (社会人) 投稿日時 2015/11/3 10:14:39
Dim Line As String = Reader.ReadToEnd 'CSVの一行

この時に、ファイルの最後まで読み込んでいるからでは?

また、提示されたコードだと、その部分を修正しても、最後のものしか表示されない
ことになると思いますが、それでいいのでしょうか?

CSVから問題情報を読み込む部分と表示部分は別にしないとダメだと思います。
投稿者 ポン吉  (高校生) 投稿日時 2015/11/4 16:27:23
PostalCode = Items(0)                    
             Label1.Text = Items(0)
つまりこの部分を変えればよいということですか?
すみませんVBを始めてまだ日が浅いのでよくわかりません
投稿者 ななしん  (社会人) 投稿日時 2015/11/4 18:19:04
まず、ReadToEndメソッドですが、これは現在位置からファイルの最後までを読み込むものです。
ですので、
  Dim Line As String = Reader.ReadToEnd 'CSVの一行
この部分でLineにファイルの全部を読み込んでしまい、
  Line = Reader.ReadLine                  '次の行を読み込む。
の部分では読み込むものがすでにない状態になってしまっています。
ですので、Reader.ReadToEndの部分をReadLineメソッドに変更すれば、最初の1行を読み込むことになります。


次にループ内の処理ですが、現状ですと2回目のループ以降(2行目以降の時)に
各変数やラベル等が上書きされて残らない状態になります。
ですので、読み込んだ内容を配列等に格納した後、表示する時はそこから表示するという流れになると思います。
投稿者 ポン吉  (高校生) 投稿日時 2015/11/5 16:15:27
とりあえず移動はできたのですが、毎回1行飛ばしになってしまいます。
ななしんさんの言っている配列について格納のやり方が調べてもよくわかりません。
よろしければ教えてください
投稿者 ななしん  (社会人) 投稿日時 2015/11/6 09:54:34
現状どのようなプログラムになっているか分かりませんが、

第41回 実行の一時停止とデバッグ
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard41.htm

を見て、ご自分のプログラムがどのように動いているか把握されることをお勧めします。
1行飛ばしで処理されるのであれば、Do~Loopの中の処理で無駄にReadLineが呼ばれている箇所が
あるのではないかと思います。

また、配列等への格納のやり方ですが、

第50回 いろいろなクラス・構造体
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard50.htm

を参照して、1つの問題の情報を格納する場所を作成し、これを

第27回 配列
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard27.htm
第28回 コレクション
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard28.htm

を見て、配列やコレクションなどに格納するのがいいと思います。

例)問題情報を格納する構造体を作成し、それをコレクションに格納する一部です

   Private Structure 問題情報
        Dim 質問 As String
        Dim 選択肢1 As String
         ・
         ・
         ・
         ・
    End Structure

    Private クイズ問題 As New List(Of 問題情報)

         ・
         ・
         ・
         ・


     '質問等をコレクションに格納する 
    Dim work As 問題情報

    work.質問 = Items(0)
    work.選択肢1 = Items(1)
         ・
         ・
         ・
         ・

    クイズ問題.Add(work)



     '1問目の情報を表示 
  Label1.Text = クイズ問題(0).質問
    Button2.Text = クイズ問題(0).選択肢1
         ・
         ・
         ・
         ・

  
投稿者 ポン吉  (高校生) 投稿日時 2015/11/9 12:01:05
すみません見てもよくわかりません。
コレクションに格納せずにやる方法はありませんか?
投稿者 ななしん  (社会人) 投稿日時 2015/11/9 12:48:50
コレクションに格納せずにというのであれば
Private 問題() As String
Private 選択肢1() As String

というふうに各項目ごとに配列にし、ループ内で
ReDim Preserve 問題(問題数)
ReDim Preserve 選択肢1(問題数)

と配列のサイズを変更しつつ読み込むという流れになるかと思います。

Private 問題() As String
Private 選択肢1() As String
     ・
     ・
     ・

 Private Sub 問題読込()
        Dim Reader As New IO.StreamReader("作品の問題点.csv", System.Text.Encoding.GetEncoding("Shift-JIS"))
        Dim Items() As String                'CSVの各項目を表す配列 
        Dim Line As String = Reader.ReadToEnd 'CSVの一行 
        Dim Count As Integer = 0

        Do Until IsNothing(Line)
     ReDim Preserve 問題(Count)
     ReDim Preserve 選択肢1(Count)
        ・
        ・
        ・

            Items = Line.Split(",")                   
            問題(Count)= Items(0)                    
            選択肢(Count)= Items(1)                    
        ・
        ・
        ・

            Line = Reader.ReadLine                  '次の行を読み込む。 
            '問題数を+1する 
      Count += 1
        Loop
        Reader.Close()
    End Sub 


投稿者 魔界の仮面弁士  (社会人) 投稿日時 2015/11/9 14:54:36
> Dim PostalCode As String
「PostalCode」って、郵便番号のことですよね。


> コレクションに格納せずにやる方法はありませんか? 
「何問目」を表示するのかを管理するための
Integer 変数を用意し、そこまで読み飛ばすとか。


Imports System.IO
Imports System.Text
Public Class Form1
    'CSV にヘッダ行がある場合は 1、ヘッダが無い場合は 0 にする。 
    Private Const FirstLine As Integer = 0

    'クイズファイルの csv のパス 
    Private quizFile As String

    '次に読み取る問題の番号(この場所まで 
    Private nextLine As Integer = FirstLine

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.quizFile = "作品の問題点.csv"
        'Me.quizFile = "C:\Temp\test.txt" 
        ShowQuiz()
    End Sub

    Private Sub ShowQuiz()
        'Skip メソッドを使って、ファイル上の 
        'nextLine 行目までのデータを読み飛ばす 
        Dim quiz = File.ReadLines(Me.quizFile, Encoding.GetEncoding("Shift_JIS")).Skip(Me.nextLine).FirstOrDefault()

        If String.IsNullOrEmpty(quiz) Then
            'データが無ければおしまい 
            MessageBox.Show("全問終了です""終了", MessageBoxButtons.OK, MessageBoxIcon.None)
            Label1.Text = ""
            Button1.Text = ""
            Button2.Text = ""
            Button3.Text = ""
            Button1.Tag = Nothing
            Button2.Tag = Nothing
            Button3.Tag = Nothing
            Me.nextLine = FirstLine
        Else
            'データがあれば、カンマで 5 列に分割して表示 
            Dim items() As String = quiz.Split(",")

            '問題文 
            Label1.Text = items(0)

            '選択肢1~3 
            Button1.Text = items(1)
            Button2.Text = items(2)
            Button3.Text = items(3)

            '回答 
            Button1.Tag = items(4)
            Button2.Tag = items(4)
            Button3.Tag = items(4)
        End If
    End Sub


    'Button1~3 が押されたときのイベント 
    Private Sub Answer_Click(sender As Object, e As EventArgs) Handles Button1.Click, Button2.Click, Button3.Click

        Dim btn As Button = DirectCast(sender, Button)
        If btn.Tag IsNot Nothing Then
            If btn.Text = CStr(btn.Tag) Then
                MessageBox.Show("""正解", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Else
                MessageBox.Show("""間違い", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            End If

            '次の問題に移る 
            Me.nextLine += 1
        End If

        ShowQuiz()
    End Sub

End Class
投稿者 YuO  (社会人) 投稿日時 2015/11/9 16:18:27
処理をIterator関数にして,自分でIEnumeratorを回すことで出題していくとか。
Iterator関数の中であまり処理しすぎると追うのが大変になりますが……。
投稿者 ポン吉  (学生) 投稿日時 2015/11/11 17:07:50
魔界の仮面弁士さんのコードを少し書き換えれば、特定の問題をランダムに表示できるんですよね?
コードを参考にやってみます!
投稿者 shu  (社会人) 投稿日時 2015/11/12 16:22:19
> 特定の問題をランダムに表示できるんですよね?
この目的は初めて出てきたないようなのでそれまでの回答に
対してちょっと直せばよいというのは出来たとしても効率が
悪い可能性があります。目的としているものがあるなら最初から
出しておいたほうがよいです。


ランダムに問題を出すなら既出のコレクション(正確にはリストですが)
を使用した方がよいです。何故コレクションが駄目なのかわかりませんが。


メモリ節約するのならそもそもReadToEndとかReadLinesは不適切ということに
なってしまいます。固定長の形式にして各問題の位置を計算で簡単に求められ
るようにしてその位置へシークするような動きにする必要が出てきます。
投稿者 wiki  (社会人) 投稿日時 2015/11/12 16:59:11
> 何故コレクションが駄目なのかわかりませんが。

おそらく、コレクションがダメ、ということではなく、
コレクションについての理解が足りない、というところではないでしょうか?
そうだとしても、今回のランダムに出題する場合においては、最低限、配列を使うべきでしょう。

あるいは、コレクションの概念を学校の授業でまだ習っていなくって、
これを使うと余所で質問したことが先生にバレるとか(笑)
投稿者 ポン吉  (高校生) 投稿日時 2015/11/12 17:07:25
昨日の質問は
'次の問題に移る 
Me.nextLine += 1
のところを少しいじればファイル内のいろいろな項目をランダムに表示できますかという意味で聞きました。誤解させたようですいません
投稿者 wiki   (社会人) 投稿日時 2015/11/12 17:23:24
> Me.nextLine += 1
> のところを少しいじればファイル内のいろいろな項目をランダムに表示できますかという意味で聞きました。

その通りで、確かにnextLineを任意の数字にすれば、任意の問題を出題できます。
ただし、正直なところ、これは非効率です。

まず、出題の度に元ファイルを読み込まなければならないこと、
次に、問題数がいくつあるかを確認するだけの目的でも
元ファイルを読み込まなければならないこと
(もちろん、問題数が固定でプログラム上でも固定になっていれば別だけれど、
問題数が増えた場合、プログラムも修正しなければならない)

もし、コレクション(最低でも配列)を使えば、
データは配列化されているので、いちいちファイル読込を行わなくとも
好きな番号の問題を取りだせるし、
読み込まれた問題数もコレクションのItem.Countや配列のLengthですぐ分かります。

もちろん、読み込んだ問題データをボタンクリックのタイミングで利用するためには、
例えばForm内のPrivate変数に格納していつでも使えるようにする必要はありますが。
投稿者 ポン吉  (高校生) 投稿日時 2015/11/26 18:12:43
CSVファイルを読み込む際に、1行目が連続で読み込まれます。2回目に表示した後はきちんと2行目から表示されます。どうすればよろしいですか?
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2015/11/27 16:51:30
> どうすればよろしいですか? 

ステップ実行などを利用して、
「どうしてそうなってしまうのか」を調査して下さい。
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard41.htm

どのように処理されているのかを把握しなければ、
修正すべき箇所も特定できませんよね。

ですから、現状のコードがどのような順序で実行されており、
その時々で、変数にどのような値が格納されているのかを
把握することが、最初にやるべきことだと思います。



> 2回目に表示した後はきちんと2行目から表示されます。
各変数の値を、初回実行時と2回目とで比較してみて下さい。
データの読み込みを始める前の段階で、変数の内容が異なっていませんか?
投稿者 ポン吉  (社会人) 投稿日時 2015/11/27 17:06:25
すみません訂正します。
行ではなく、列でした。
投稿者 daive  (社会人) 投稿日時 2015/11/29 14:46:40
余計な御世話かもですが、
場を無償で使わせていただいている、感謝の気持ちを表すためにも、
質問を建てて、回答がついて居るものについては、
キチンと対処しましょう。不要になった質問であれば、解決済みにしましょう。

るきおさんは、この有用なサイトの主催者、管理者です。

終了したCSVについて
 http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=25962
投稿者 (削除されました)  () 投稿日時 2015/12/15 13:38:49
(削除されました)