자바(JAVA)/미니 프로젝트 & 기초 공부

Java 기초 다시 공부하기 1주차-수강관리 프로그램 메뉴 선택 구현, 대통령 취임사 알파벳 별 출현 빈도 구현

개발학생 2024. 6. 9. 23:38
반응형

1. 수강관리 프로그램 메뉴 선택 구현

1) 조건

  • 숫자만 입력하고 그 외 입력은 하지 않음
  • Scanner 클래스의 nextInt 함수 이용
  • 시작화면은 다음과 같이 구현(이미지 참고)
    • 1 입력 후 엔터 -> "회원 관리 메뉴를 선택했습니다." 출력 후 다시 시작 화면으로
    • 2 입력 후 엔터 -> "과목 관리 메뉴를 선택했습니다." 출력 후 
    • 3 입력 후 엔터 -> "수강 관리 메뉴를 선택했습니다." 출력 후 다시 시작 화면으로
    • 4 입력 후 엔터 -> "결제 관리 메뉴를 선택했습니다." 출력 후 다시 시작 화면으로
    • 5 입력 후 엔터 -> "프로그램을 종료합니다." 출력 후 프로그램 종료
    • 그외 숫자 입력 후 엔터 -> "입력값이 정확하지 않습니다."  출력 후 다시 시작 화면으로

2) 코드

import java.util.Scanner;

public class JavaSurpriseTask01 {
    public static void main(String[] args) {
        // 1주차 자바 깜짝 과제-수강생 이소미
        // 수강관리 프로그램 메뉴 선택
        
        // 무한반복문(5를 누를 때까지 계속 메뉴 선택 가능)
        while (true) {
            System.out.println("<<<<[메뉴선택]>>>>");
            System.out.println("1. 회원 관리");
            System.out.println("2. 과목 관리");
            System.out.println("3. 수강 관리");
            System.out.println("4. 결제 관리");
            System.out.println("5. 종료");
            System.out.println();
            System.out.println("1~5번 중 원하시는 메뉴의 숫자를 입력하세요 > ");

			// 사용자에게서 숫자 입력받기
            Scanner sc = new Scanner(System.in);
            int menu = sc.nextInt();
            
            // 5를 누르면 프로그램 종료
            if (menu == 5) {
                System.out.println("프로그램을 종료합니다.");
                break;
            } else {
                switch (menu) {
                    // 1을 누르면 회원 관리 메뉴 선택
                    case 1:
                        System.out.println("회원 관리 메뉴를 선택했습니다.");
                        System.out.println();
                        break;
                    // 2를 누르면 과목 관리 메뉴 선택
                    case 2:
                        System.out.println("과목 관리 메뉴를 선택했습니다.");
                        System.out.println();
                        break;
                    // 3을 누르면 수강 관리 메뉴 선택    
                    case 3:
                        System.out.println("수강 관리 메뉴를 선택했습니다.");
                        System.out.println();
                        break;
                    // 4를 누르면 결제 관리 메뉴 선택
                    case 4:
                        System.out.println("결제 관리 메뉴를 선택했습니다.");
                        System.out.println();
                        break;
                    // 1~5 외에 다른 숫자를 입력하면 출력되는 문구    
                    default:
                        System.out.println("입력값이 정확하지 않습니다.");
                        System.out.println();
                        break;
                }
            }
        }
    }
}

3) 출력 결과

4) 회고

사실 최근에 이 코드와 비슷하게 야구 게임 프로그램을 구현해본 적이 있어서, 그 코드를 참고해서 쉽게 작성할 수 있었던 것 같다.

출력 결과 가독성을 위해 switch문에서 System.out.println();을 한번 더 하고 break를 넣었는데, 지금 생각해보니 윗줄의 System.out.println("[문자열]") 속에.. 문자열 뒤에 \n을 붙이면 되지 않나 싶다.... 다음엔 참고해야겠다.

 

그리고 다른 분 코드를 보니, 유지보수성을 생각하시고 메뉴 출력 부분과 프로그램 동작 부분을 메서드 여러 개로 따로 분리하신 분이 있더라... 멋졌다. 나도 분명 메서드를 배웠었는데... 다음엔 유지보수성도 고민해봐야겠다.

 


2. 대통령 취임사 알파벳 별 출현 빈도 구현

1) 조건

  • 다음 글을 텍스트 파일에 넣어 문장의 각 영문 알파벳 별 출현 빈도의 개수를 구하고, 전체알파벳 중 몇 % 비율로 나오는지 구하기(이미지 참고)
    • 전체 문자열의 길이는 String.length() 함수 사용
    • 문자열(String)에서 특정 자리의 문자를 가져오는 String.charAt(index) 함수를 이용
    • 영문 알파벳의 대소문자는 구분하지 않음
    • 출력 형식을 아래 이미지처럼 맞추기
    • 내용은 텍스트 파일에서 읽어오고, 파일에서 텍스트를 읽어오는 소스는 추가 클래스 참조 

2) 코드

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.List;

// 1주차 자바 깜짝 과제 2번-수강생 이소미
// 대통령 취임사 알파벳 별 출현 빈도

// 파일 읽어오는 클래스 (제로베이스 제공)
class FileUtils {
    public String getLoadText(String filePath) {
        // 내부 버퍼를 사용하여 문자열을 저장하고 수정하는 클래스
        StringBuilder sb = new StringBuilder();

        try {
            // 주어진 파일 경로에서 파일을 읽어옴
            Path path = Paths.get(filePath);
            // 파일의 모든 줄을 리스트로 읽어옴
            List<String> lines = Files.readAllLines(path);

            for (int i = 0; i < lines.size(); i++) {
                if (i > 0) {
                    // 줄 사이에 개행 문자 추가(줄바꿈)
                    sb.append("\n");
                }
                // 각 줄을 StringBuilder에 추가
                sb.append(lines.get(i));
            }
        } catch (IOException e) {
            // 예외 발생 시 스택 트레이스 출력
            e.printStackTrace();
        }
        // 파일 내용을 문자열로 반환
        return sb.toString();
    }
}

public class JavaSurpriseTask02 {

    public static void main(String[] args) {
        // FileUtils 클래스로 객체 생성
        FileUtils file = new FileUtils();
        // FileUtils 클래스 내부 메서드로 파일 내용 읽어오기
        String filePath = file.getLoadText("C:/president_speech.txt/");
        // 대소문자 구분 없이 세기 위해 모두 대문자로 변경
        filePath = filePath.toUpperCase();

        // 알파벳 빈도 저장을 위한 정수 배열 (A-Z, a-z)
        int[] alphabets = new int[26];
        // 전체 알파벳 수를 저장할 변수
        int sum = 0;

        // 파일 내용의 모든 문자 검사
        for (int i = 0; i < filePath.length(); i++) {
            // 현재 아스키코드 숫자에 맞는 알파벳 반환
            char letter = (char) (filePath.charAt(i));
            // 알파벳인 경우 카운팅
            if (Character.isLetter(letter)) {
                //'A'로부터 몇 번째인지 계산
                alphabets[letter - 'A']++;
                // 알파벳의 총 개수 증가
                sum++;
            }
        }
        // 각 알파벳의 빈도와 비율 출력
        for (int i = 0; i <= filePath.length(); i++) {
            // 각 아스키코드 숫자에 맞는 알파벳 반환
            String letter = ((char) ('A' + i)) + "=";
            // 소수점 둘째 자리까지 반올림하는 DecimalFormat 생성
            DecimalFormat df = new DecimalFormat("#.##");
            float percent = ((float) alphabets[i] / sum) * 100;

            // 숫자를 문자열로 변환하고 공백을 추가하여 자릿수 맞추기
            String countStr = String.format("%6d" + "개, ", alphabets[i]);
            String percentStr = String.format("%8s", df.format(percent) + "%");

            System.out.println(letter + countStr + percentStr);
        }
    }
}

3) 출력 결과

4) 회고

이 문제에서 여러모로 많이 헤맸던 것 같다.

 

일단 저 텍스트 파일을 따로 다운받아야 하는 건가 싶어서 구글링을 했는데 .txt 파일이 어디에도 없어서 멘붕이 왔다..

한참 뒤져보다가 지푸라기라도 잡는 심정으로 저 이미지의 글자를 드래그해봤는데 당연하게도 복사가능하게 되어 있었다... 민망했다. 메모장을 열고 내용에 복사 붙여넣기 해서 텍스트 파일을 만들 수 있었다.

 

출력하고 보니 예제 이미지랑 %부분만 달라서 좀 당황했는데, 확인해보니 저 %가 나오게 하려면 파일 전체를 다 읽어온 것을 세어 sum 변수에 담아야 했고 내 sum 변수의 값은 그것보다 1000정도 작았다.

근데 파일에서 알파벳만 전부 세는 거면 파일 전체보다 개수가 적어야 하는 게 당연하지 않나 싶어서 그냥 그대로 제출했다.. 마지막에 Exception이 발생하긴 했는데 원인을 모르겠고 내용은 전부 정상출력 되길래 패스했다... 

 

문자열 포맷 부분에서 printf를 쓰지 않고 여러 개 변수에 출력할 내용들 전부 담은 후 변수명만 println()안에 담고 다른 문자열과 합쳐서 출력했는데, 이유는 단순하다. printf에 넣으면 필연적으로 코드가 가로 한 줄로 길어지게 되는데 나는 그게 가독성이 떨어진다고 느껴져서 거부감이 들기 때문이다(...) 

소수 둘째 자리까지 표시하는 부분에서 Math.round 함수를 쓰지 않은 이유도 위와 같다. 코드가 가로 한 줄로 길어져 가독성이 떨어져 보인다. 그리고 MySQL에 더 익숙해서 그런지 Java의 round 함수에선 'round(실수,자릿수)' 형식이 안 되고 'round(실수)' 형식만 되기 때문에 100을 곱한 뒤 100을 나눠야 하는 게 너무 번거롭다...ㅠㅋㅋㅋㅋ

 

휴... 분명 파일 읽기는 다른 강의에서 배운 적이 있었는데, 제공받은 파일 클래스 코드가 잘 이해되지 않는 데다가 코드 추가를 어떻게 해야 할 지 감이 오질 않아 구글링과 Chat GPT의 힘을 많이 빌렸다...

내가 스스로 코드를 아예 고민해보지도 않은 건 아니지만 좀 부끄러웠다.

이런 훌륭한 도구들이 나올 만큼 문명이 많이 발달해서 다행이다...

 

 

 

반응형