質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.53%

  • Ruby

    7620questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

文の意味

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 492

yusuke.

score 56

見ていただきありがとうございます。
この文の一文一文が、どういう働きをしているのかがよくわかりません。
英単語のプログラムを作っています。
一応、ファイルの中にある文を、@monndaiのなかなどにいれて表示させようとするプログラムの一部です。

def yomikomi()
   i = 0
   j = 0
   @moji =[]
   f = open("./dat/#{@jikkoufile}","r") 
 while text = f.gets do
   @moji[i] = text.chomp
   i += 1
 end
  f.close
  @mondaisu = i/2
 while j <= i/2
    eval("@q#{j} = [@moji[j*2+0],@moji[j*2+1]]")
    j += 1
 end


 q = []
 eval("q = @q#{rand(@mondaisu)}.clone")
 @mondai     = q[0]
 @kotae      = q[1]

 @matigai = open("./dat/matigai.dat","a")
end


これ以外の文の書き方とかってありますか。
あと、eval が具体的にどんな働きをしているのかなど教えていただけると嬉しいです。
---追記
日本語を表示して、その英単語を入力して、それが正しいかどうかを判断するというプログラムを作りたいです。
原型はできているのですが、今のままだと、ファイルを、一つしか選択できないので、複数のファイルを一気に読みこんで、ランダムに表示させるということがしたいです。

休み
vacation
takeの過去
took
catchの過去
caught
seeの過去
saw
魚釣りに行く
go fishing
庭
garden
伝統的な
traditional
初めて
for the first time
am,isの過去
was
areの過去
were


問題の文はこのように、日本語、英語の順に1行ずつかいてあります。

コードを全文出します。

#! ruby -Ks
require "color_echo"

@score = 0
@count = 0
@naoshi = Array.new
@jikkoufile = Array.new

def yomikomi()
   i = 0
   j = 0
   @moji =[]
   f = open("./dat/#{@jikkoufile}","r") 
 while text = f.gets do
   @moji[i] = text.chomp
   i += 1
 end
  f.close
  @mondaisu = i/2
 while j <= i/2
    eval("@q#{j} = [@moji[j*2+0],@moji[j*2+1]]")
    j += 1
 end


 q = []
 eval("q = @q#{rand(@mondaisu)}.clone")
 @mondai     = q[0]
 @kotae      = q[1]

 @matigai = open("./dat/matigai.dat","a")
end


def hon

 filenames = Dir.open("dat").to_a
 puts filenames
 puts "reset"

  puts "\n\nやりたいファイルを選択してください。"
   @jikkoufile << gets.chomp
   puts @jikkoufile
     while true do
        if filenames.include?(@jikkoufile)
           puts " ほかにもファイルを選択しますか。 y or n"
           filesentaku = gets.chomp
            if filesentaku == "y"
                puts "入力してください。"
             jikkoufile2 = gets.chomp
                unless filenames.include?(jikkoufile2)
                  CE.once.fg :red
                  puts "そのファイルは存在しません。"
                else 
                  @jikkoufile.push(jikkoufile2)
                end
             redo
          elsif filesentaku == "n"
             break
          else
            CE.once.fg :red
            puts "入力するならyを、しないならnを入力してください。"
            redo
          end
        end

       if @jikkoufile == "reset"
          puts "Reset matigai.dat"
          File.open("dat/matigai.dat","w")
          sleep 2
          exit
       end
       CE.once.fg :red
       puts "再入力してください"
       @jikkoufile << gets.chomp
     end

  puts "何回実行しますか?"
  @a = gets.chomp.to_i
  puts "次の日本語を英語に直しなさい"
  count = 0
  while true do 
    yomikomi
    puts @mondai
    s = gets.chomp

    puts "正解は#{@kotae}です。"
    sleep 1

    if s == @kotae
      puts "正解です    "
      @score = @score + 1
    else
      @count = @count + 1
      CE.once.fg :red
      puts "間違いです。\n"
      @naoshi.push(@mondai,@kotae)
    end
  count = count + 1
    if count >= @a
      puts "\n\n終了です","\n#{@a}問中、#{@score}問正解しました"
    unless @naoshi.empty?    #empty? は何もなかったらtrueを返す
      CE.once.fg :index47
      puts "間違えた問題  復習しておこう!"
      CE.bg :blue
      puts @naoshi
      @matigai.puts @naoshi
      else 
       CE.rainbow
       puts "----------------------------------------------"
       puts "全問正解!!おめでとう!"
       puts "----------------------------------------------"
    end
   exit
  end
 end
end
hon


インデントとかをうまく使えてなくて読みにくいですが、すいません。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yusuke.

    2017/04/19 17:41

    実行ファイルを見せることは可能です。

    キャンセル

  • yusuke.

    2017/04/19 17:42

    全部の文を表示した方がいいですか。

    キャンセル

  • yusuke.

    2017/04/19 17:47

    全部のソースを表示した方が

    キャンセル

回答 2

+3

提示されたコードに可能な限りコメントをつけてみました

def yomikomi()
  # インデックスの初期化
  i = 0
  j = 0

  # 配列の初期化
  @moji =[]

  # 実行ファイルのオープン(読み取り設定)
  f = open("./dat/#{@jikkoufile}", 'r')

  # ファイル終端までテキストの読み込み
  while text = f.gets do
    # 配列に実行ファイルの行を読み込み(読み込み後は次の行を指す)
    @moji[i] = text.chomp
    # インデックスのインクリメント
    i += 1
  end
  # 読み込み終わったので実行ファイルの開放
  f.close

  # 問題数を計算して代入
  @mondaisu = i/2

  # 問題数の分だけ問題と答えを読み込み
  while j <= i/2
    # インスタンス変数にデータを配列として代入
    # @q0 = [問題, answer]
    # @q1 = [問題2, answer2]...
    # (データの中身は不明)
    eval("@q#{j} = [@moji[j*2+0],@moji[j*2+1]]")
    j += 1
  end


  # 問題と答えを代入する配列を初期化
  q = []
  # 問題集の中から問題と答えをランダムに抽出
  eval("q = @q#{rand(@mondaisu)}.clone")
  @mondai = q[0]
  @kotae  = q[1]

  # 間違いをファイルに記録できるよう、ファイルを追加モードで開く
  @matigai = open("./dat/matigai.dat", 'a')
end

2点、気になるところがありました

可能であれば、eval の使用は極力控えたほうがいいかもしれません
だいたいは他の方法で実装できますし、また、想定・意図しない入力によってセキュリティ的に問題のあるコードが実行されてしまうかもしれません

それと、インスタンス変数(@variable_name)を、あたかもグローバル変数かのように使用するのも、コードの可読性・メンテナンス性の面から避けられるべきでしょう


仮に私が書くとすればこう書く、といった例です
(※イメージを伝えたかったので、実際には動かない部分があるかもしれません)

class QA
  # 問題と答えのペアを保持する雛形
  QASet = Struct.new(:question, :answer)

  # クラスのインスタンス生成時の初期設定
  def initialize(qa_file_name = 'qa.txt')
    @question_and_answers = read_question_and_answers
    @questions_count = @question_and_answers.size
    @qa_file_name = qa_file_name
  end

  # 問題集の中から問題と答えをランダムに抽出
  def take_question_and_answer_set
    questions_index = rand(@questions_count)
    @question_and_answers[questions_index]
  end

  # 問題と答えのペアを一行ごとに表示
  def print_question_and_answers
    @question_and_answers.each do |qa_set|
      puts "#{qa_set.question}:\t#{qa_set.answer}"
    end
  end

  private

  def read_question_and_answers
    # 問題と答えのファイルの読み込み
    question_and_answers_file = File.read("./dat/#{@qa_file_name}")

    # 読み込んだデータを問題と答えのセット、その集合に変換
    question_and_answers =
      question_and_answers_file
      .lines
      .each_slice(2) { |question, answer| QASet.new(question, answer) }

    question_and_answers
  end

  # def wrong_answers_file
  #   # 間違いをファイルに記録できるよう、ファイルを追加モードで開く
  #   open('./dat/matigai.dat', 'a')
  # end
end

qa = QA.new
qa_set = qa.take_question_and_answer_set
p qa_set.question # => 日本語単語
p qa_set.answer # => 英語単語

# qa.print_question_and_answers # 問題と答えのセットを一覧表示

以上、なにか参考になれば幸いです


 Links

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/20 15:28

    ありがとうございます。
    なぜevalはあまりつかはないほうがいいのでしょうか。

    キャンセル

  • 2017/04/20 15:34

    追記しました。また見ていただけると嬉しいです。

    キャンセル

checkベストアンサー

0

単語テスト1.txt

休み
vacation
takeの過去
took
catchの過去
caught
seeの過去
saw
魚釣りに行く
go fishing
庭
garden
伝統的な
traditional
初めて
for the first time
am,isの過去
was
areの過去
were


単語テスト2.txt

ナポリタン
パスタ


単語テスト3.txt

らーめん
しお
#encoding: utf-8

def wordTest(array)
  puts "次の問題に答えよ"
  loop{
    all_clear = 0
    huse = []
    puts ""
    array.each do |q, a|
      print "#{q}:"
      answer = gets.chomp.to_s
      if answer == a then
        puts "〇正解!"
        all_clear += 1
      else
        puts"X不正解!"
        print"正解を見ますか?[y/n]:"
        userselect = gets.chomp.to_s.tr("Y", "y")
        if userselect == "y"; puts a; end
        huse << [q, a]
      end
      puts "-" * 20
      puts ""
    end
    if all_clear == array.length
      puts "全問正解!!"
      break
    else
      puts "#{array.length}問中#{all_clear}問正解しました!!"
      puts "間違った問題は復習しておこう!!"
      array = huse
    end
  }
end

def selectFiles()
  puts "単語テストをしますか?[y/n]"
  userselect = gets.chomp.to_s.tr("N", "n")
  if userselect == "n"; exit; end
  puts ""
  files = Dir.glob("問題集/*.txt")
  if files.none?; puts "問題集がありません。"; exit; end
  puts "やりたい問題を選択してください。"
  files.each_with_index do |element, i|
    puts "#{i + 1}:\s#{File.basename(element)}"
  end
  userselect = gets.chomp.to_s.split("\s").map{|e| e.to_i - 1}
  puts ""
  tmp = []
  userselect.each do |element|
    if element > files.length || element < 0
      element = 1
    end
      tmp << File.read(files[element]).chomp.split("\n").each_slice(2).to_a
  end
  return tmp.flatten(1).shuffle
end

wordTest(selectFiles())


単語試験プログラムを作ってみました。
問題集というフォルダの中に単語テスト.txtなどの
問題が書かれたテキストファイルを入れて使います。

単語テスト.txtの選択は半角英数字で区切り文字はスペースです。

可読性が高いとか処理が速くなるなどのメリットは一切ありません。

補足

userselect = gets.chomp.to_s.split("\s").map{|e| e.to_i - 1}
全体の意味:
選択してもらった結果をuserselectに入れる。

細かい説明:
1.利用者は表示された問題集の一覧から「半角英数字」でファイルを選択する。
 結果はこのようになる「1 2 3 4 5」(数字と数字の間は半角スペース。)

2.getsで入力された文字列を取得。末尾の改行文字をchompでとってto_sで文字列化する。

3.splitを使って入力された文字列を半角スペースで区切る。
 結果はこのようになる「[1, 2, 3, 4, 5]」(配列になる。)

4.mapは配列の要素を入れ替える時に使う。今回は、3の配列の要素が1つずつeに入る。
 e = e.to_i - 1みたいなことが行われて、3の配列の要素が全て交換される。

5.最終的にuserselectは
 userselect = [0, 1, 2, 3, 4]
  みたいな配列になる。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/20 15:30

    回答ありがとうございます。
    ごめんなさい。質問の仕方が悪かったです。
    このプログラムで、日本語を表示して、その英単語を入力して正解かどうかを判断するというプログラムなんです。
    追記しときます。

    キャンセル

  • 2017/04/20 17:46

    いえいえ。追記された内容に対応しました。

    キャンセル

  • 2017/04/21 16:09

    回答ありがとうございます。
    userselect = gets.chomp.to_s.split("\s").map{|e| e.to_i - 1}
    この文の意味がよくわかりません。教えてください。

    キャンセル

  • 2017/04/21 18:43 編集

    見た目を重視して、ファイルを選択するときの数字を1からにしています。
    配列は0から始まるので配列の1番目は0番です。
    userselect = gets.chomp.to_s.split("\s").map{|e| e.to_i - 1}
    この部分で利用者に入力してもらった数字から1引くことで
    配列の数字と合わせています。
    puts "#{i + 1}:\s#{File.basename(element)}"を
    puts "#{i}:\s#{File.basename(element)}"とすることで
    userselect = gets.chomp.to_s.split("\s").map(&:to_i)
    にできます。(-1しなくてよくなる。)

    回答にも説明を追加しました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    7620questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。