다양한 표기법이 존재합니다.

이러한 표기법을 다른 표기법으로 수작업으로 변경은 개수가 적은 경우에는 문제가 없지만 많은 경우 시간도 많이 걸리고 오류가 날 수도 있습니다.

다음은 각 표기법을 비교한 표입니다.


표기법 형식 예시 설명 사용 예시 (언어/분야)
Camel Case camelCase 첫 단어 소문자, 이후 단어 대문자 Java, JavaScript, C# 변수 및 함수명
Pascal Case PascalCase 모든 단어 첫 글자 대문자 C#, Java 클래스명
Snake Case snake_case 단어 사이 _ 사용, 소문자 Python 변수 및 함수명
Screaming Snake Case SCREAMING_SNAKE_CASE Snake Case + 대문자 상수 값 (MAX_SIZE)
Kebab Case kebab-case 단어 사이 - 사용, 소문자 URL, CSS 클래스명 (my-class-name)
Train Case Train-Case Kebab Case + 단어 첫 글자 대문자 문서 제목, UI 요소 (Menu-Item)
Dot Notation dot.notation 단어 사이 . 사용 설정 파일, 도메인 (config.file.path)
Hungarian Notation strUserName 변수 유형 접두사 (str, i, b) 오래된 C, C++ 코드 (iCount, bIsValid)
MACRO Case #DEFINE MAX_VALUE C 스타일 매크로 C/C++ 전처리기 (#DEFINE, #INCLUDE)

이 표를 보면 어떤 표기법이 어떤 상황에서 적절한지 쉽게 비교할 수 있습니다

1) 코드 생성

코드 생성 시 사용한 ChatGPT 프롬프트입니다.

다음 기능을 수행하는 python 코드를 pyqt5 를 사용하여 작성해주세요.
작성 후 에러도 테스트해주세요.

1. window 타이틀은 JbDesk 로 표시
2. window 메뉴에 "줄단위", "표기법"을 추가합니다.
"줄단위" 하위에는 "줄 공백 제거" 를 추가합니다.
"표기법" 하위에는 "camelCase", "snake_case", "PascalCase", "SCREAMING_SNAKE_CASE", "kebab-case", "Train-Case", "dot.notation" 를 추가합니다.

3. Window 내부에는 
첫째 라인에 선택한 Tool 기능 텍스트를 표시하고 
둘째 라인에는 "입력" 이라는 GroupBox 와 내부에 TextEdit 를 표시
세번째 라인에는 "변환"이라는 버튼을 표시합니다.
"변환" 버튼은 "변환"이라는 글자크기 만큼 버튼을 표시합니다.
다섯째 라인에는 "출력" 이라는 GroupBox 와 내부에 TextEdit 를 표시
4.
"줄 공백 제거"를 선택하고 "변환" 버튼을 누르면 "입력" 의 text 의 줄 공백을 제거하여 "출력" text 에 표시합니다.
"camelCase" 를 선택하고 "변환" 버튼을 누르면 "입력" 의 text 의 camelCase로 변환하여 "출력" text 에 표시합니다.
"snake_case" 를 선택하고 "변환" 버튼을 누르면 "입력" 의 text 의 snake_case로 변환하여 "출력" text 에 표시합니다.
"PascalCase" 를 선택하고 "변환" 버튼을 누르면 "입력" 의 text 의 PascalCase로 변환하여 "출력" text 에 표시합니다.
"SCREAMING_SNAKE_CASE" 를 선택하고 "변환" 버튼을 누르면 "입력" 의 text 의 SCREAMING_SNAKE_CASE로 변환하여 "출력" text 에 표시합니다.
"Train-Case" 를 선택하고 "변환" 버튼을 누르면 "입력" 의 text 의 Train-Case로 변환하여 "출력" text 에 표시합니다.
"dot.notation" 를 선택하고 "변환" 버튼을 누르면 "입력" 의 text 의 dot.notation로 변환하여 "출력" text 에 표시합니다.

 

아래 코드는 다음과 같이 다운받을 수 있습니다.

git clone git@github.com:jbpark/jbDeskExample.git
cd jbDeskExample/jbDesk/ch1.2
import re
import sys

from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QTextEdit, QPushButton, QLabel, QVBoxLayout, QWidget, \
    QGroupBox, QHBoxLayout


def remove_line_spaces(text):
    return '\n'.join([line for line in text.splitlines() if line.strip()])


def to_snake_case(text):
    text = re.sub(r'([a-z])([A-Z])', r'\1_\2', text)  # camelCase -> snake_case
    text = re.sub(r'[-\s]', '_', text)  # kebab-case, space -> snake_case
    return text.lower()


def to_camel_case(text):
    words = to_snake_case(text).split('_')
    return words[0] + ''.join(word.capitalize() for word in words[1:])


def to_pascal_case(text):
    words = to_snake_case(text).split('_')
    return ''.join(word.capitalize() for word in words)


def to_kebab_case(text):
    return to_snake_case(text).replace('_', '-')


def to_screaming_snake_case(text):
    return to_snake_case(text).upper()


def to_train_case(text):
    return '-'.join(word.capitalize() for word in to_snake_case(text).split('_'))


def to_dot_notation(text):
    words = re.split(r'[\s_\-]+', text)
    return ".".join(word.lower() for word in words)


class JbDesk(QMainWindow):
    def __init__(self):
        super().__init__()
        self.selected_option = "줄 공백 제거"  # 기본값
        self.initUI()

    def initUI(self):
        self.setWindowTitle("JbDesk")
        self.setGeometry(300, 300, 1200, 900)

        # 메뉴바 생성
        menubar = self.menuBar()

        # "줄단위" 메뉴
        line_menu = menubar.addMenu("줄단위")
        strip_action = QAction("줄 공백 제거", self)
        strip_action.triggered.connect(lambda: self.set_option("줄 공백 제거"))
        line_menu.addAction(strip_action)

        # "표기법" 메뉴
        format_menu = menubar.addMenu("표기법")
        formats = [
            "camelCase", "snake_case", "PascalCase", "SCREAMING_SNAKE_CASE",
            "kebab-case", "Train-Case", "dot.notation"
        ]
        for fmt in formats:
            action = QAction(fmt, self)
            action.triggered.connect(lambda checked, f=fmt: self.set_option(f))
            format_menu.addAction(action)

        # 메인 위젯 설정
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout()

        # 선택된 기능 표시
        self.option_label = QLabel(f"선택된 기능: {self.selected_option}")
        layout.addWidget(self.option_label)

        # 입력 GroupBox
        input_group = QGroupBox("입력")
        input_layout = QVBoxLayout()
        self.input_text = QTextEdit()
        input_layout.addWidget(self.input_text)
        input_group.setLayout(input_layout)
        layout.addWidget(input_group)

        # 변환 버튼
        button_layout = QHBoxLayout()
        self.convert_button = QPushButton("변환")
        self.convert_button.setFixedSize(50, 30)
        self.convert_button.clicked.connect(self.convert_text)
        button_layout.addWidget(self.convert_button)
        layout.addLayout(button_layout)

        # 출력 GroupBox
        output_group = QGroupBox("출력")
        output_layout = QVBoxLayout()
        self.output_text = QTextEdit()
        output_layout.addWidget(self.output_text)
        output_group.setLayout(output_layout)
        layout.addWidget(output_group)

        central_widget.setLayout(layout)

    def set_option(self, option):
        """메뉴에서 선택된 옵션을 설정"""
        self.selected_option = option
        self.option_label.setText(f"선택된 기능: {self.selected_option}")

    def convert_text(self):
        """선택된 옵션에 따라 입력 텍스트를 변환"""
        text = self.input_text.toPlainText()
        if not text:
            self.output_text.setPlainText("입력 값이 없습니다.")
            return

        if self.selected_option == "줄 공백 제거":
            result = self.remove_line_spaces(text)
        elif self.selected_option == "camelCase":
            result = self.to_camel_case(text)
        elif self.selected_option == "snake_case":
            result = self.to_snake_case(text)
        elif self.selected_option == "PascalCase":
            result = self.to_pascal_case(text)
        elif self.selected_option == "SCREAMING_SNAKE_CASE":
            result = self.to_screaming_snake_case(text)
        elif self.selected_option == "kebab-case":
            result = self.to_kebab_case(text)
        elif self.selected_option == "Train-Case":
            result = self.to_train_case(text)
        elif self.selected_option == "dot.notation":
            result = self.to_dot_notation(text)
        else:
            result = "알 수 없는 변환 옵션입니다."

        self.output_text.setPlainText(result)

    @staticmethod
    def remove_line_spaces(text):
        """줄 공백 제거"""
        return remove_line_spaces(text)

    @staticmethod
    def to_camel_case(text):
        """camelCase 변환"""
        lines = text.strip().split("\n")  # 줄 단위로 분리
        return "\n".join([to_camel_case(line) for line in lines])

    @staticmethod
    def to_snake_case(text):
        """snake_case 변환"""
        lines = text.strip().split("\n")  # 줄 단위로 분리
        return "\n".join([to_snake_case(line) for line in lines])

    @staticmethod
    def to_pascal_case(text):
        """PascalCase 변환"""
        lines = text.strip().split("\n")  # 줄 단위로 분리
        return "\n".join([to_pascal_case(line) for line in lines])

    @staticmethod
    def to_screaming_snake_case(text):
        """SCREAMING_SNAKE_CASE 변환"""
        lines = text.strip().split("\n")  # 줄 단위로 분리
        return "\n".join([to_screaming_snake_case(line) for line in lines])

    @staticmethod
    def to_kebab_case(text):
        """kebab-case 변환"""
        lines = text.strip().split("\n")  # 줄 단위로 분리
        return "\n".join([to_kebab_case(line) for line in lines])

    @staticmethod
    def to_train_case(text):
        """Train-Case 변환"""
        lines = text.strip().split("\n")  # 줄 단위로 분리
        return "\n".join([to_train_case(line) for line in lines])

    @staticmethod
    def to_dot_notation(text):
        """dot.notation 변환"""
        lines = text.strip().split("\n")  # 줄 단위로 분리
        return "\n".join([to_dot_notation(line) for line in lines])


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = JbDesk()
    window.show()
    sys.exit(app.exec_())

 

2) 코드 실행

Posted by 제이브레인
,

회사에서 일을 하다보면 간단한 작업 이지만 귀찮은 일들이 많습니다.

예를 들면 글을 복사했는데 중간 중간에 공백라인이 1개씩 추가되어 있는 경우 이를 제거하려면 문서 편집 프로그램에서 하나하나 제거를 하거나 이를 제거하기 위한 프로그램들을 활용하여 정규식등으로 제거를 했습니다.

그런데 이런 작업이 생각보다 많더군요.

그냥 툴을 하나 만들면 좋겠다는 생각이 들어서 만들게되었습니다.

프로그램은 Java, C++, Python 등을 고민했는데 Java 는 실행파일 만들기가 귀찮고 C++ 은 Visual Studio 설치하는 것이 너무 시간이 많이 걸리고 OS 마다 특성을 타서 추가적인 작업이 필요했습니다.

그래서 제일 만만한 Python 을 선택하게 되었습니다.

우선 빈줄 제거 기능을 만들었습니다.

라인에 빈줄이 있는 경우 이를 제거하는 기능입니다.

브라우저로 화면 갈 무리 후에 붙여 넣기를 하면 빈줄이 추가되는 경우가 있습니다.

이를 제거할 때 사용하면 좋습니다.

1) 코드 생성

ChatGPT 에 다음 프롬프트를 사용하였습니다.

다음 기능을 수행하는 python 코드를 pyqt5 를 사용하여 작성해주세요.
작성 후 에러도 테스트해주세요.

1. window 타이틀은 JbDesk 로 표시
2. window 메뉴에 "변환"을 추가하고 Tool 하위에 "공백 줄 제거", "대문자로" 를 추가
3. Window 내부에는 
첫째 라인에 선택한 Tool 기능 텍스트를 표시하고 
둘째 라인에는 "입력" 이라는 GroupBox 와 내부에 TextEdit 를 표시
세번째 라인에는 변환이라는 버튼을 표시
다섯째 라인에는 "출력" 이라는 GroupBox 와 내부에 TextEdit 를 표시
4. Tool 로 "공백 줄 제거" 를 선택하고 변환 버튼을 누르면 "입력" Text 에서 공백을 제거 후에 "출력" text 에 표시
5. Tool 로 "대문자로" 를 선택하고 변환 버튼을 누르면 "입력" Text 에서 대문자 변환 후 "출력" text 에 표시

생성된 코드는 다음과 같습니다.

아래 코드는 다음과 같이 다운받을 수 있습니다.

git clone git@github.com:jbpark/jbDeskExample.git
cd jbDeskExample/jbDesk/ch1.1
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QTextEdit, QHBoxLayout, QLabel, QGroupBox, QMenuBar, QMenu, QStatusBar
from PyQt5.QtCore import Qt


class JbDeskApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout()

        # 메뉴 바 생성
        self.menu_bar = QMenuBar(self)
        tool_menu = self.menu_bar.addMenu("변환")

        self.action_remove_blank = tool_menu.addAction("공백 줄 제거")
        self.action_to_upper = tool_menu.addAction("대문자로")

        self.action_remove_blank.triggered.connect(lambda: self.set_mode("공백 줄 제거"))
        self.action_to_upper.triggered.connect(lambda: self.set_mode("대문자로"))

        layout.addWidget(self.menu_bar)

        # 첫째 라인: 선택한 Tool 기능 텍스트 표시
        self.tool_label = QLabel("공백 줄 제거", self)
        layout.addWidget(self.tool_label)

        # 둘째 라인: Input GroupBox와 TextEdit
        self.input_groupbox = QGroupBox("입력", self)
        input_layout = QVBoxLayout()
        self.input_text = QTextEdit(self)
        input_layout.addWidget(self.input_text)
        self.input_groupbox.setLayout(input_layout)
        layout.addWidget(self.input_groupbox)

        # 세 번째 라인: 변환 버튼
        button_layout = QHBoxLayout()
        self.convert_button = QPushButton("변환", self)
        self.convert_button.setFixedSize(50, 30)
        self.convert_button.clicked.connect(self.convert_text)
        button_layout.addWidget(self.convert_button)
        layout.addLayout(button_layout)

        # 다섯째 라인: Output GroupBox와 TextEdit
        self.output_groupbox = QGroupBox("출력", self)
        output_layout = QVBoxLayout()
        self.output_text = QTextEdit(self)
        self.output_text.setReadOnly(True)
        output_layout.addWidget(self.output_text)
        self.output_groupbox.setLayout(output_layout)
        layout.addWidget(self.output_groupbox)

        self.set_mode("공백 줄 제거")
        self.setLayout(layout)
        self.setWindowTitle("JbDesk")
        self.setGeometry(300, 300, 1200, 900)

    def set_mode(self, mode):
        self.mode = mode
        self.tool_label.setText(mode)
        self.input_text.clear()
        self.output_text.clear()

    def convert_text(self):
        text = self.input_text.toPlainText()

        if self.mode == "공백 줄 제거":
            result = '\n'.join([line for line in text.splitlines() if line.strip()])
        elif self.mode == "대문자로":
            result = text.upper()
        else:
            result = text

        self.output_text.setPlainText(result)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = JbDeskApp()
    ex.show()
    sys.exit(app.exec_())

 

2) 환경 설정

위 코드는 pyqt5 패키지를 사용합니다.

ChatGPT 에 다음 프롬프트를 사용하였습니다.

jbdesk.py 파일이 있습니다.
windows 에서 다음을 실행하는 bat 파일을 만들어주세요.
conda env 이름이 jbdesk38_64 이라는 이름이 존재하지 않으면 생성합니다.
jbdesk38_64 을 활성화 합니다.
jbdesk38_64 에 pyqt5 패키지를 설치합니다.
jbdesk.py 를 실행합니다.

 

생성된 bat 파일입니다.

run.bat

@echo off
set CONDA_ENV_NAME=jbdesk38_64

:: Conda 활성화
call conda activate base

:: Conda 환경 목록 확인 후 존재하지 않으면 생성
conda info --envs | findstr /C:"%CONDA_ENV_NAME%" >nul
if %errorlevel% neq 0 (
    echo Creating conda environment: %CONDA_ENV_NAME%
    conda create -y -n %CONDA_ENV_NAME% python=3.8
)

:: Conda 환경 활성화
call conda activate %CONDA_ENV_NAME%

:: PyQt5 설치
pip show PyQt5 >nul 2>nul
if %errorlevel% neq 0 (
    echo Installing PyQt5...
    pip install PyQt5
)

:: jbdesk.py 실행
python jbdesk.py

3) 에러 수정

실행 시 다음과 같은 에러가 발생할 수 있습니다.

CondaError: Run 'conda init' before 'conda activate'

anaconda3 설치 후에 3개의 폴더가 path 에 설정되어 있어야 합니다.

해당 설정이 없는 경우 발생 할 수 있습니다.

 

다음과 같이 DLL 에러가 발생하는 경우 오류 수정 방법입니다.

Traceback (most recent call last):
  File "jbdesk.py", line 3, in <module>
    from PyQt5.QtWidgets import (QApplication, QMainWindow, QAction, QTextEdit,
ImportError: DLL load failed while importing QtWidgets: %1은(는) 올바른 Win32 응용 프로그램이 아닙니다.

 

우선 pyqt5 를 재설치해보는 방법이 있습니다.

아래 명령으로 어떤 qt5 가 설치되었는지 확인합니다.

pip list
Package          Version
---------------- -----------
click            8.1.8
colorama         0.4.6
numpy            1.24.4
pandas           2.0.3
pip              24.2
PyQt5            5.15.9
pyqt5-plugins    5.15.9.2.3
PyQt5-Qt5        5.15.2
PyQt5_sip        12.15.0
python-dateutil  2.9.0.post0
pytz             2025.1
qt5-applications 5.15.2.2.3
qt5-tools        5.15.2.1.3
setuptools       75.1.0
six              1.17.0
tzdata           2025.1
wheel            0.44.0

 

위와 같이 pip list 로 설치된 pip 들을 확인할 수 있습니다.

qt5 라고 되어 있는 것은 모두 uninstall 하고 pyqt5 를 다시 설치합니다.

pip uninstall PyQt5
pip uninstall pyqt5-plugins
pip uninstall PyQt5-Qt5
pip uninstall PyQt5_sip
pip uninstall qt5-applications
pip uninstall qt5-tools
pip install PyQt5

 

또는 Visual C++ Redistributable 를 설치가 제대로 되지 않아서 발생할 수 있습니다.

PyQt5는 msvcp140.dll, vcruntime140.dll 같은 Windows 런타임 라이브러리를 필요로 합니다.
마이크로소프트 공식 페이지에서 Visual C++ Redistributable을 설치하세요.

 

4) 코드 실행

run.bat

 

실행 시 아래와 같이 입력에 text 를 입력하면 해당 text 라인 중에 공백 라인이 있으면 제거합니다.

이제는 유틸리티 제작도 인공지능 프로그램으로 손쉽게 만들 수 있네요.

'유틸리티 > JbDesk' 카테고리의 다른 글

JbDesk 1.6편-코드 리팩터링  (1) 2025.03.28
JbDesk 1.5편-exe 만들기  (0) 2025.03.28
JbDesk 1.4편-tray 기능 추가  (0) 2025.03.28
JbDesk 1.3편-로그 timezone 변경  (0) 2025.03.27
JbDesk 1.2편-표기법 변환  (2) 2025.03.27
Posted by 제이브레인
,

Qt Designer 로 xxx.ui 의 경우 Designer 툴로 편집하는 장점은 있으나 동적 UI 생성이 어려운 점이 있었습니다.

예를 들면 windows 를 확대하거나 축소 시를 고려하는 것이 어렵더군요.

선택 기준 Qt Designer 사용 코드 작성
빠른 UI 개발 ✅ 유리 ❌ 불리
UI 변경이 잦음 ❌ 불리 ✅ 유리
동적 UI 생성 ❌ 불리 ✅ 유리
초보자 접근성 ✅ 유리 ❌ 불리
버전 관리 편의성 ❌ 불리 ✅ 유리
복잡한 애니메이션 ❌ 불리 ✅ 유리

그래서 xxx.ui 를 코드 작성하는 것으로 변경하였습니다.

1) 코드 생성

xxx.ui 파일을 전체를 복사 후에 아래와 같은 ChatGPT 프롬프트를 사용하였습니다.

다음은 python Qt designer 로 만들어졌습니다.
이를 .ui 파일이 아닌 .py 파일로 수정해주세요.
accountBalance, accountStocks 는 우측  layout 으로 표시해주세요.

코드 생성 후 다음과 같이 추가적인 프롬프트를 사용하였습니다.

브라우저를 종료 후에 입력하지 말고 기존 프롬프트 창에 계속 입력하면 됩니다.

accountBalance 의 경우 table 이 2라인입니다. window 확대 시에 table 이 2 라인인 것을 고려하여 확대해주세요.
accountStocks 에 2행 3열의 table 은 보입니다. 그런데 나머지 부분이 횐색으로 표시됩니다. 2행 3열의 table 크기에 맞추어 횐색 부분의 크기를 줄여주세요.

 

전체 코드는 아래 git 에서 확인 할 수 있습니다.

git clone https://github.com/jbpark/JbTraderExample.git
cd JbTraderExample/jbtrader/ch5.12

 

2) 코드 실행

실행 결과 확대 축소 시에 정렬이 잘되는 것을 확인 할 수 있습니다.

Posted by 제이브레인
,