업무중에 분기별로 한번씩 학생들이 읽은 책 로그에 들어가서
각자 읽은 책이 몇권인지 확인, 엑셀 시트에 입력해야 하는 업무가 있다.
마우스 스크롤 올려가며 하나하나 세다보니 혼이 나갈거 같음.
하다가 숫자 까먹으면 현타 팍 옴.
이러게 살 순 없다.
AI와 책 권수 확인하는 툴을 만들어보기로 했다.
대충 내 고충사항을 말하고
한번 알려주는 코드 하나하나 써보겠다고 제안했더니
한땀 한 땀 알려줌.
나는 거기에 맞춰 모이 줏어먹는 새 마냥 한 알 한 알 줏어먹으면서 코드 쳤더니만
어느새 뭔가가 구현은 되고있음.
JFrame으로 프레임 만들고, 기능 넣고,
거기에다 스크롤 기능도 달고.
출력물이 콘솔이 아닌 프레임에 표시되도록 하고.
이것 저것 하는데 진짜 신기하긴 신기하구만.
그리고 누군가에게 줄게 아니라 내가 사용할거여서 잡다구리한 기능이나 아름다운 디자인은 불필요해서 안심중
만들다 보니까 내가 써왔던 모든것이 하나하나 사실 기느응로 채워진것이 너무 신기하다.

출력물이 프레임에 표시될 때 스크롤을 이용할 수 있도록 스크롤을 만들어줬음

하지만 스크롤 창이 너무 작아서 한줄씩 밖에 표시가 안된다.


그래서 AI가 창을 나눠서 스크롤 할 수 있도록 코드를 알려줬다.
JScrollPane scrollPane = new JScrollPane(textArea);
JScrollPane resultScrollPane = new JScrollPane(resultArea);
JSplitPane splitPane =
new JSplitPane(
JSplitPane.VERTICAL_SPLIT,
scrollPane,
resultScrollPane
);
splitPane.setDividerLocation(250);


이정도 만들고 나니 이제 거의 마무리 단계
AI는 남은 TASK중 뭘 하고싶냐고 묻길래 다 하자고 했다.

초기화 버튼 과 복사버튼 추가해줬다.
특히 복사할 때 전체 복사는 불필요하고, 딱 최종적으로 읽은 권수만 필요하기 때문에 (NumberButton을 변수로 하는 권수용 버튼을 하나 더 추가했다.) (최종 권수 변수는 uniqueCount임)
clearButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textArea.setText("");
resultArea.setText("");
}
});
copyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String result = resultArea.getText();
StringSelection selection = new StringSelection(result);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null);
}
});
copyNumberButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StringSelection selection = new StringSelection(String.valueOf(uniqueCount));
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null);
}
});
regex 안정화
변경 전
Pattern pattern = Pattern.compile("^(.*?)\\s\\d");
| # | 기호 | 의미 |
| 1 | ^ | 문자열 시작부터 |
| 2 | (.*?) | 글자를 최대한 짧게 모으라 (책 제목 후보군) |
| 3 | \s | 공백 |
| 4 | \d | 숫자 |
"문자열 처음부터 시작해서 숫자 나오기 직전까지 글자를 모아주렴!"
문제점: 제목뒤에 숫자가 나오면 데이터를 제대로 인식하지 못함.
변경 후
Pattern pattern = Pattern.compile("^(.*?)\\s\\d\\.\\d\\s\\d+L");
| # | 기호 | 의미 |
| 1 | ^ | 문자열 시작부터 |
| 2 | (.*?) | 글자를 최대한 짧게 모으라 (책 제목 후보군) |
| 3 | \s | 공백 |
| 4 | \d | 숫자 |
| 5 | \d\.\d | 4.3 같이 생긴 점수 (ATOS 점수) |
| 6 | \d+L | 670L (lexile) |
"'ATOS 점수 + Lexile 점수' 이 구조가 나오기 진전까지가 제목이니까 제목만 잘 추출해보렴!"
내가 사용할 데이터 모양이 정해져 있어서, regex를 설정하는데 어렵지 않음. 물론 ai가 해줌
Snowboard Struggle 4.3 670L 1:39:31 5:01 PM, 4/17/26 6:16 PM, 4/19/26
The Dragon with the Girl Tattoo 3.1 390L 0:18:18 9:40 PM, 4/12/26 10:02 PM, 4/12/26
The Girl Who Breathed Fire 3.0 460L 0:00:05 9:40 PM, 4/12/26 9:40 PM, 4/12/26
WCMX Daredevil 2.5 400L 0:15:53 6:01 PM, 6/2/25 12:35 PM, 4/4/26
Paintball Boss 4.4 670L 1:21:32 9:55 PM, 3/31/26 8:45 PM, 4/1/26
All About Baseball 3.4 670L 0:13:37 8:54 PM, 3/22/26 9:10 PM, 3/22/26
귀신수학 제 3권 4.1 550L 0:12:00 1:00 PM, 4/11/26 1:20 PM, 4/11/26
해리포터 2 5.0 800L 0:50:00 2:00 PM, 4/12/26 3:00 PM, 4/12/26
귀신수학 제 3권 4.1 550L 0:33:00 4:00 PM, 4/13/26 4:50 PM, 4/13/26
Magic School Bus 2 4.1 550L 0:12:00 1:00 PM, 4/11/26 1:20 PM, 4/11/26
History of World War 2 5.0 800L 0:50:00 2:00 PM, 4/12/26 3:00 PM, 4/12/26
Magic School Bus 2 4.1 550L 0:33:00 4:00 PM, 4/13/26 4:50 PM, 4/13/26
최종 코드
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
public class App {
static int uniqueCount = 0;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(500, 400);
frame.setTitle("Book Counter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea textArea = new JTextArea();
JScrollPane scrollPane = new JScrollPane(textArea);
JButton button = new JButton("분석하기");
JButton clearButton = new JButton("초기화");
JButton copyButton = new JButton("복사하기");
JButton copyNumberButton = new JButton("최종 권 수 복사");
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
buttonPanel.add(clearButton);
buttonPanel.add(copyButton);
buttonPanel.add(copyNumberButton);
JTextArea resultArea = new JTextArea();
JScrollPane resultScrollPane = new JScrollPane(resultArea);
resultArea.setEditable(false);
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, resultScrollPane);
splitPane.setDividerLocation(250);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String text = textArea.getText();
String[] lines = text.split("\n");
int totalBooks = 0;
int number = 1;
Set<String> uniqueBooks = new HashSet<>();
Set<String> duplicateBooks = new HashSet<>();
for (String line : lines) {
line = line.trim();
if (!line.equals("")) {
Pattern pattern = Pattern.compile("^(.*?)\\s\\d\\.\\d\\s\\d+L");
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
String title = matcher.group(1);
if (!uniqueBooks.add(title)) {
duplicateBooks.add(title);
}
System.out.println(number + ". " + title);
}
totalBooks++;
number++;
}
}
clearButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textArea.setText("");
resultArea.setText("");
}
});
copyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String result = resultArea.getText();
StringSelection selection = new StringSelection(result);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null);
}
});
copyNumberButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StringSelection selection = new StringSelection(String.valueOf(uniqueCount));
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null);
}
});
System.out.println("중복책 목록: ");
for (String book : duplicateBooks) {
System.out.println("- " + book);
}
uniqueCount = uniqueBooks.size();
int duplicateCount = totalBooks - uniqueCount;
System.out.println("총 권 수: 총 " + totalBooks + "권");
String resultText = "총 권 수: " + totalBooks + "권\n" + "중복 권 수: " + duplicateCount + "권\n" + "중복 제외 권 수: "
+ uniqueCount + "권\n\n" + "중복 책 목록: \n";
for (String book : duplicateBooks) {
resultText += "- " + book + "\n";
}
resultArea.setText(resultText);
System.out.println("증복 도서 권 수: 총 " + duplicateCount + "권");
System.out.println("중복 제외 권 수: 총 " + uniqueCount + "권");
}
});
frame.add(splitPane);
frame.add(buttonPanel, "North");
frame.setVisible(true);
}
}
일단 이렇게 생겼고.




복사하기 기능.
복사하면 result 전체가 복사되기도 하고,
사실상 내가 실무에 필요한 숫자만 딱 (핑크색) 복사가 가능하다.


일단 코드는 다 만들었다.
ai 도움 받으니 되는구만 . 이제 원래 의도했던대로 exe 로 만들기만 하면 된다.
'콤퓨타 > 뚝딱뚝딱' 카테고리의 다른 글
| [Book Counter] 자바코드 .exe 생성 (0) | 2026.05.24 |
|---|---|
| 02. Emo 창 만들기 (Swing) (2) | 2025.08.11 |
| 01. EmoPro 개요 (4) | 2025.08.11 |