🤗
【Java入門】簡単英語学習CLIツールを制作したゾ
簡単英語学習CLIツール
背景
私はチャロや短編英ドラマ等で英語の学習をしていました
学習メモは以下の形式でメモり、復習をする際は英語部分を隠して、日本語を翻訳していました
Please don't say that
そんなこといわないで
little doggie
小さな犬
いちいち英語を隠して、実施すること自体が 面倒くさい と思ったこと、
出題パターンが日本語からの翻訳のみではワンパターンで答えの暗記 となり、
復習の精度が低い と思い自己学習用に開発へ取り組みました
非エンジニア向け
ツールの使用方法
本ツールは日本語と英語のデータセット(txt)を読みこみ、
2種類の出題パターンより問題を出します。
以下形式のテキストを ~/document/java/EnglishManager/ へ格納する
English
英語
問題は以下のように出題され、回答後答えも出力される
虫食い問題 | 虫食い問題(答え) | 翻訳問題 | 翻訳問題(答え) |
---|---|---|---|
エンジニア向け
開発環境
- エディタ
- vscode
- java version
- 21.0.2
クラス概要
- App.java
- マネージャとユーザの操作
- 英語アプリの流れを担っている
- Manager.java
- ユーザーに名前を尋ねる
- ユーザー情報を登録
- ユーザー名を記憶すること
- ユーザーへ挨拶をすること
- 問題を用意してあることを確認すること
- 問題群を取得すること
- 問題の準備をすること
- 問題の答えを取得すること
- 問題を実施すること
- ManagerInterface.java
- マネージャクラスのインターフェース
- ManagerLogic.java
- 虫食い問題の作成ロジック
- 翻訳問題の作成ロジック
- User.java
- 出題してほしい問題番号を伝えること
- 問題に答えること
クラス図
TBD
苦労したところ
- 問題点
- Scannerクラスのインスタンスは一度 close すると再利用不可
- 解決策
- Scannerインスタンスは使いまわす
◆ App.java
Scanner sc = new Scanner(System.in); //"Shift-JIS"
User.choseNumberForQuestion(sc);
User.answerQuiz(sc);
◆ User.java
public int choseNumberForQuestion(Scanner sc){
if(sc.hasNextInt()){
int QuestionNumber = sc.nextInt();sc.nextLine();
return QuestionNumber;
}//..省略
}
public String answerQuiz(Scanner sc){
System.out.print("回答 > ");
if(sc.hasNextLine()){
String questionAnswer = sc.nextLine();
return questionAnswer;
}//..省略
}
- 問題点
- インターフェースをimplementする際は引数も合わせなければいけない
- 解決策
- interfaceの引数をClassと合わせる
◆ ManagerInterface.java
public interface ManagerInterface(){
void askForUserName(Scanner sc);//ユーザーに名前を尋ねる
void registUserInfo(String name);//ユーザー情報を登録
}
◆ Manager.java
public class Manager implements ManagerInterface(){
public void askForUserName(Scanner sc){
//省略
}
public void registUserInfo(String name){
//省略
}
}
- 問題点
- Stringに特定位置の文字列置き換えメソッドがない
- 解決策
-
java.lang.StringBuilder
を利用する
-
StringBuilder replaceWord = new StringBuilder();
String word = "abcd";
replaceWord.append(word);
replacLeafWarblerWord.replace(0,1,"A");
// before:word=abcd , after:word=Abcd
- 問題点
- ArrayListの値格納と取得は配列の要素指定ではなくメソッドを利用する
- 解決策
- ArrayListの値を格納・取得の際はメソッドを利用する
new List<String> arrays = new ArrayList<String>(); //宣言
answer.add("ABC"); //値の格納
answer.get(0); //値の取得
ソースコード
- App.java
import java.io.File;
import java.util.List;
import java.util.Scanner;
public class App {
public static void main(String[] args) throws Exception {
Manager mn = new Manager();
User us = new User();
String checkedUserInfoAnswer = mn.checkUserInfo();
Scanner sc = new Scanner(System.in, "Shift-JIS");
if(checkedUserInfoAnswer.equals("NotFound")){//User未登録
mn.askForUserName(sc);
}else{
mn.setUserName(checkedUserInfoAnswer);
mn.helloUser();
}
mn.checkDataSetDir();
File[] files = mn.getDataSetFiles();
if(files.length > 0){
mn.presentsQuetionsFile(files); // Manager : 問題のデータセットを提示する
int questionNumber = us.choseNumberForQuestion(sc); // User : 問題のデータセットより対象を選ぶ
String questionReady = mn.questionReady(questionNumber,files);
if(questionReady.equals("OK")){
ManagerLogic lg = mn.useManagerLogic();
List<String> questions = mn.createQuestion(lg);
List<String> answers = mn.getAnswer(lg);
mn.quizExits(questions,answers,us,sc);// Manager : 問題を出題する User : 一問一答で回答する。
//mn.setLog();// 回答ログを記録する
}
}else{
System.out.println("datasetフォルダに問題ファイルを1つ以上格納してください");
}
sc.close();
}
}
- ManagerInterface.java
import java.io.File;
import java.util.List;
import java.util.Scanner;
public interface ManagerInterface {
void askForUserName(Scanner sc);//ユーザーに名前を尋ねる
void registUserInfo(String name);//ユーザー情報を登録
void setUserName(String content);//ユーザー名をフィールドにセットする
void helloUser();//ユーザーに挨拶
String checkDataSetDir();//問題データが存在することを確認
File[] getDataSetFiles();//問題データセット群を取得する
void presentsQuetionsFile(File[] files);//問題データセット群を表示する
String questionReady(int questionNumber,File[] files);//問題(試験)の準備をする
ManagerLogic useManagerLogic();//Logicを利用する
List<String> createQuestion(ManagerLogic lg);//問題(試験)を作成する
List<String> getAnswer(ManagerLogic lg);//問題(試験)の答えを取得する
void quizExits(List<String> questions,List<String> answers,User us,Scanner sc);//問題(試験)を実施する
}
- Manager.java
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Manager implements ManagerInterface{
private String userInfoFilePath = "./userinfo.txt";
private String dataSetFilePath = "./dataset/";
public String userName;
public int numberOfQuestion = 0;
private String questionDatas;
public Manager(){
}
public String checkUserInfo(){
Path path = Paths.get(userInfoFilePath);
try{
String content = Files.readString(path);
return content;
}catch(IOException e){
return "NotFound";
}
}
public void askForUserName(Scanner sc){
System.out.println("あなたの名前を教えてください");
System.out.print("名前 > ");
if(sc.hasNext()){
String userName = sc.next();
registUserInfo(userName);
System.out.println(userName + "さん これからよろしくお願いします。");
this.userName = userName;
}
}
public void registUserInfo(String name){
try{
File f = new File(this.userInfoFilePath);
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
bw.write("name:" + name);
bw.close();
}catch(IOException e){
System.out.println("RegistUserInfoError\n" + e.getMessage());
}
}
public void setUserName(String content){
Pattern p = Pattern.compile("name:(.*)");
Matcher match = p.matcher(content);
if(match.matches()){
this.userName = match.group(1);
}
}
public void helloUser(){
System.out.println(this.userName + "さん よろしくお願いします。");
}
public String checkDataSetDir(){
Path path = Paths.get(dataSetFilePath);
if(Files.exists(path)){
return "OK";
}else{
try{
Files.createDirectory(path);
}catch(IOException e){
System.out.println("DataSetCreateError: " + e.getMessage());
}
return "NotFound";
}
}
public File[] getDataSetFiles(){
File dir = new File(dataSetFilePath);
File[] files = dir.listFiles();
return files;
}
public void presentsQuetionsFile(File[] files){
System.out.println("出題してほしいファイル番号を選んでください");
for(int i=0; i<files.length;i++){
if(i%2==0){
System.out.print(i+1 + " : " + files[i] + " ");
}else{
System.out.println(i+1 + " : " + files[i] + " ");
}
}
}
public String questionReady(int questionNumber,File[] files){
String filePath = files[questionNumber-1].toString();
Path path = Paths.get(filePath);
try{
String questionData = Files.readString(path);
questionData = ManagerLogic.deleteEmptyLine(questionData);
this.questionDatas = questionData;
this.numberOfQuestion = ManagerLogic.countLines(questionData)/2;
return "OK";
}catch(IOException e){
return "NotFound";
}catch(Exception e){
return "NotFound";
}
}
public ManagerLogic useManagerLogic(){
ManagerLogic lg = new ManagerLogic(this.questionDatas);
return lg;
}
public List<String> createQuestion(ManagerLogic lg){
System.out.println("\n\n\n試験開始 ("+"問題数: " + this.numberOfQuestion+")"+"\n---------");
System.out.println("");
List<String> Questions = lg.questionFormat();//問題の作成
return Questions;
}
public List<String> getAnswer(ManagerLogic lg){
return lg.getAnswer();
}
public void quizExits(List<String> questions,List<String> answers,User us,Scanner sc){
for(int i=0; i<questions.size();i++){
System.out.println(questions.get(i));
System.out.println(us.answerQuiz(sc));
System.out.println(answers.get(i));
}
}
}
- ManagerLogic.java
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.lang.StringBuilder;
public class ManagerLogic {
public List<String> japanese = new ArrayList<String>();
public List<String> english = new ArrayList<String>();
private List<String> answer = new ArrayList<String>();
public ManagerLogic(String questions){
String[] splitLineQuestion = questions.split("\n");
for (int i=0;i<splitLineQuestion.length;i++){
if(i%2 == 0){
this.english.add(splitLineQuestion[i]);
}else{
this.japanese.add(splitLineQuestion[i]);
}
}
}
public static int countLines(String str){
String[] lines = str.split("\r\n|\r|\n");
return lines.length;
}
public static String deleteEmptyLine(String content){
content = content.replaceAll("(\n|\r|\n\r|\r\n){2,}", "\n");
content = content.replaceAll("[ \t\\x0B\f]+(\n|\r|\n\r|\r\n)", "");
if(content.substring(content.length() - 1).equals("\n")){
content=content.substring(0,content.length()-1);
}
return content;
}
public List<String> questionFormat(){
List<String> wantToLogicBaseQuestions = new ArrayList<String> ();
List<String> wantToLogicQuestions = new ArrayList<String> ();
List<String> presenterQuestionsTranslation = new ArrayList<String> ();
List<String> questionBaseLanguage = new ArrayList<String>();
List<String> questionLanguage = new ArrayList<String>();
int numberQuestionPattern = 2;
int startQuestionAdd = 0;
int endQuestionAdd = 0;
int numberQuestionSection = this.japanese.size()/numberQuestionPattern;
for(int j=0;j<numberQuestionPattern;j++){
int numberFormat = j;
wantToLogicBaseQuestions = new ArrayList<String> ();//値を初期化
wantToLogicQuestions = new ArrayList<String> ();
startQuestionAdd = (j) * numberQuestionSection;//0~3,3~6,6~9
endQuestionAdd = numberQuestionSection * (j+1);
questionBaseLanguage = judgeQuestionBaseLanguage(numberFormat);
questionLanguage = judgeQuestionLanguage(numberFormat);
for(int i=startQuestionAdd; i<endQuestionAdd;i++){
wantToLogicBaseQuestions.add(questionBaseLanguage.get(i));
wantToLogicQuestions.add(questionLanguage.get(i));
}
//ランダム問題に問題番号と問題を入力。問題セットを返してくる。
presenterQuestionsTranslation.addAll(RandomQuestionLogic(numberFormat,wantToLogicBaseQuestions,wantToLogicQuestions));
}
if(this.japanese.size() % numberQuestionPattern != 0){
int numberOfQuestion = numberQuestionSection*numberQuestionPattern;
int numberFormat = 0;
wantToLogicBaseQuestions = new ArrayList<String> ();//値を初期化
wantToLogicQuestions = new ArrayList<String> ();
questionBaseLanguage = judgeQuestionBaseLanguage(numberFormat);
questionLanguage = judgeQuestionLanguage(numberFormat);
for(int i=numberOfQuestion; i<this.japanese.size();i++){
wantToLogicBaseQuestions.add(questionBaseLanguage.get(i));
wantToLogicQuestions.add(questionLanguage.get(i));
presenterQuestionsTranslation.addAll(RandomQuestionLogic(numberFormat,wantToLogicBaseQuestions,wantToLogicQuestions));
}
}
return presenterQuestionsTranslation;
}
public List<String> judgeQuestionBaseLanguage(int numberFormat){
List<String> questionBaseLanguage = new ArrayList<String>();
switch(numberFormat){
case 1:
questionBaseLanguage = this.japanese;
break;
case 0:
questionBaseLanguage = this.english;
break;
case 2:
questionBaseLanguage = this.english;
break;
}
return questionBaseLanguage;
}
public List<String> judgeQuestionLanguage(int numberFormat){
List<String> questionLanguage = new ArrayList<String>();
switch(numberFormat){
case 1:
questionLanguage = this.english;
break;
case 0:
questionLanguage = this.japanese;
break;
case 2:
questionLanguage = this.japanese;
break;
}
return questionLanguage;
}
public List<String> RandomQuestionLogic(int numberFormat,
List<String> wantToLogicBaseQuestions,
List<String> wantToLogicQuestions
){
List<String> questionDatas = new ArrayList<String>();
switch(numberFormat){
case 1:
questionDatas.addAll(Translation(wantToLogicBaseQuestions,wantToLogicQuestions));
break;
case 0:
questionDatas.addAll(Leafwarbler(wantToLogicBaseQuestions,wantToLogicQuestions));
break;
case 2:
questionDatas.addAll(Translation(wantToLogicBaseQuestions,wantToLogicQuestions));
break;
//Leafwarbler(wantToLogicBaseQuestions);
}
return questionDatas;
}
public List<String> Disarrange(List<String> questions){
return questions;
}
public List<String> Translation(
List<String> wantToLogicBaseQuestions
,List<String> wantToLogicQuestions
){
String explanation = "Q. 次の文を翻訳してください\n";
String answerExplanation = "A.";
List<String> translationQuestion = new ArrayList<String>();
for (int i=0;i<wantToLogicBaseQuestions.size();i++){
translationQuestion.add(explanation + wantToLogicBaseQuestions.get(i));
this.answer.add(answerExplanation + wantToLogicQuestions.get(i) + "\n");
}
return translationQuestion;
}
public List<String> Leafwarbler(
List<String> wantToLogicBaseQuestions
,List<String> wantToLogicQuestions
){
List<String> LeafwarblerQuestion = new ArrayList<String>();
String[] splitBaseQuestion ;
String leafWarblerStr;//置換対象文字列
String leafWarbler = "□";//虫食い文字列
String explanation = "Q. 次の□を埋めてください\n";
String leafWarbledStr = "";
String answerExplanation = "A. ";
String answerChars = "";
String answerWard = "";
String answerChar = "";
StringBuilder replacLeafWarblerWord ;
StringBuilder replaceAnswer ;
int leafWarblerCharPosition;
int numberLeafWarblerWord;//this is a pen [t,2][i,3]
int numberLeafWarblerWordChar;
int numberReplaceChar;
for (int i=0;i<wantToLogicBaseQuestions.size();i++){
answerChars = "";
leafWarbledStr = "";
leafWarblerStr = wantToLogicBaseQuestions.get(i);
splitBaseQuestion = leafWarblerStr.split(" ");
numberLeafWarblerWord = splitBaseQuestion.length;
Random ra = new Random();
//答えの文字列を作成する
for(int j=0; j<numberLeafWarblerWord;j++){
numberLeafWarblerWordChar = splitBaseQuestion[j].length();
numberReplaceChar = numberLeafWarblerWordChar/2;
answerWard = "";
for(int l=0;l<numberLeafWarblerWordChar;l++){
//answerChars += "-";
answerWard += "-";
}
if(numberLeafWarblerWordChar>1){ //単語の文字数が1の時は置き換えない
for(int k=0;k<numberReplaceChar;k++){
replacLeafWarblerWord = new StringBuilder();
replaceAnswer = new StringBuilder();
leafWarblerCharPosition = ra.nextInt(numberLeafWarblerWordChar);
answerChar = String.valueOf(splitBaseQuestion[j].charAt(leafWarblerCharPosition));
if(!answerChar.equals(leafWarbler)){
replaceAnswer.append(answerWard);
replaceAnswer.replace(leafWarblerCharPosition,leafWarblerCharPosition+1,answerChar);
answerWard = replaceAnswer.toString();
}
replacLeafWarblerWord.append(splitBaseQuestion[j]);
replacLeafWarblerWord.replace(leafWarblerCharPosition,leafWarblerCharPosition+1,leafWarbler);
splitBaseQuestion[j] = replacLeafWarblerWord.toString();
}
answerChars += answerWard + " ";
}
leafWarbledStr += splitBaseQuestion[j] + " ";
}
answerChars = answerChars.replace("-", "");
LeafwarblerQuestion.add(explanation + wantToLogicQuestions.get(i) + "\n" + leafWarbledStr);
this.answer.add(answerExplanation + answerChars + "\n");
}
return LeafwarblerQuestion;
}
public List<String> getAnswer(){
return this.answer;
}
}
- User.java
import java.util.Scanner;
public class User{
public int choseNumberForQuestion(Scanner sc){
System.out.print("番号 > ");
if(sc.hasNextInt()){
int QuestionNumber = sc.nextInt();sc.nextLine();
return QuestionNumber;
}else{
return 0;
}
}
public String answerQuiz(Scanner sc){
System.out.print("回答 > ");
try{
if(sc.hasNextLine()){
String questionAnswer = sc.nextLine();
return questionAnswer;
}else{
System.out.println("NODATA");
return "NotData";
}
}catch(Exception e){
System.out.println(e.getMessage());
return "Error";
}
}
}
Discussion