ChatGPT 의 코딩 실력을 확인하는 목적과 Shift 코딩 연습을 목적으로 맥용 프로그램을 만들어 보았다.
◼︎ 개발 환경
- HW : MacBook Pro (14-inch, 2021)
- CPU : Apple M1 Pro
- MENORY : 16GB
- DISK : 512 GB SSD
- OS : macOS 15.0.1 (24A348)
- TOOLS : XCode 16.1
- Programming Language : Shift
◼︎ 프로그램 요구사항
맥은 UTF-8 NFD (Normalization Form Decomposed)로 저장하는 반면, 윈도우는 UTF-8 NFC (Normalization Form Composed)를 사용 하는 차이로 인하여 맥에서 생성된 파일이 윈도우로 이동하면 자모가 분리되어 보여지는 현상이다. 이를 해결하기 위하여 아래와 같은 목표를 정의했다.- Drag&Drop 기능을 활용
- 자소가 분리된(NFD) 유니코드 파일명을 자소가 조합된(NFC) 파일명으로 변환
참고로 ChatGPT 는 유료버전의 4o을 사용했고 개발 과정에서 모양과 기능은 Contact 과 반디네이머를 참고했다.
어떻게 프로그램을 만들 것인가
🆀 맥에서 생성하거나 수정한 파일의 이름이 윈도우에서 깨지는 이슈가 있는데 자동으로 변환을 해주는 맥용 앱을 만들고 싶어.
🅰
전체적으로 어떻게 만들 것인가를 자세하게 설명해주고 있다. 추가로 좀더 구체적인 질문을 하며 상세하게 원하는 것을 설명해준다.
🆀 앱을 실행하면 파일 탐색기 처럼 좌측에는 폴더 우측에서 세부 파일 구조와 NFC, NFD 을 보여주고 선택된 파일 또는 폴더에 대하여 일괄적으로 NFD 형식의 유니코드 파일명을 NFC 변경하거나 반대로 변경하는 기능으로 구현하면
🅰
프로젝트 생성
제시된 코드를 기반으로 "Namenizer" 라는 이름으로 XCode 프로젝트를 생성하였다.
다음으로는 컴파일을 통하여 코드를 실행하면서 지속적으로 코드 수정을 요청하고 이를 반복하였다.
"Namenizer" 프로그램 코딩
코딩 과정의 최초의 문제는 모든 파일들을 보여주지 못한다는 점이었다. download 등 주요한 폴더들은 표시되지 않았다.
🆀 downloads 와 같은 폴더는 접근할 수 없는데
🅰
해결방법은 크게 ❶ Sandbox 설정을 통하여 보안을 무력화 하거나 ❷ NSOpenPanel을 사용하여 사용자에게 권한 요청하는 방식을 알려주었는데 두번쨰 방법을 사용하는 것을 선택하고 제시되는 코드를 사용하여 코드를 수정했다.
두번째 문제는 반디네이머와 같이 NFD 유니코드로 인하여 윈도우에서 한글 자모가 분리되는 것을 미리 보여주는 기능을 구현하는 것이었다.
🆀 NFD 여부를 알려면
🅰
제안된 방법으로 코딩을 해보았지만 자모가 분리되어 보이지 않았다. 지루한 주고받는 방식의 질의를 통하여 알게된 유니코드 디버딩 과정에서 보여지는 텍스트와 유니코드 값의 차이를 확하게 되었다. (동일하게 보이는 텍스트가 유니코드 값이 다르게 보여짐. 보통 NFD 의 경우 유니코드 값이 더 많았다.) "그럼 유니코드 값의 동일 유무를 검사하면 되겠네" 가정을 수립하고 확인을 위한 질문을 계속한다.
🆀 항상 NFC 로만 보여지는 이유는
NFC 여부를 판단하는 방법으로 제시된 다음 코드를 기반으로 추가 질의를 하여 이 문제를 좀더 깊이 확인 해보았다.
func isNFC(_ string: String) -> Bool {
return string == string.precomposedStringWithCanonicalMapping
}
🆀 func isNFC(_ string: String) -> Bool {
return string == string.precomposedStringWithCanonicalMapping
} 코드가 항상 true 을 리턴하는 것 은
이러한 내용을 바탕으로 유니코드 값을 활용하여 NFD 정규화 상태인지 확인하는 함수는 앞서 제시된 유니코드 디버깅을 활용하여 직접 문제를 아래와 같이 해결했다.
/// 문자열이 NFD로 정규화된 상태인지 확인하는 함수
public static func isNFDUsingUnicodeScalars(_ string: String) -> Bool {
// NFD로 변환된 문자열
let nfdString = string.decomposedStringWithCanonicalMapping
// 원본 문자열과 NFD로 변환된 문자열의 유니코드 스칼라를 비교
return string.unicodeScalars.elementsEqual(nfdString.unicodeScalars)
}
이 과정에서 알게된 건 "macOS 파일 시스템에서 파일 이름을 읽어올 때는 NFD로 변환된 상태로 제공할 수 있다"라는 가능성이 있다는 것이었다.
🆀 자모가 분리되는 것을 보여주는 것은 다음 질문에 대한 답으로 해결할 수 있었다.
originalString.decomposedStringWithCanonicalMapping 해도 자모가 분리되어 보이지 않는다면
🅰 마지막 가장 큰 문제는 NFC 로 파일 이름을 변경하는 것이었다. 제시된 코드는 정상동작 하지 않아 관련하여 질문을 해보았다.
🆀 NFC 유니코드를 출력하면 다른 값으로 보이는데 파일이름을 NFC 로 저장하고 다시 읽으면 변경되어 있지 않는데
🅰 결론은 macOS 파일 시스템(APFS, HFS+)은 파일 이름을 항상 NFD로 저장하기 때문에 정상적인 방법으로는 불가하다고 판단하였다.
🆀 커멘드를 실행하여 처리하면
🆀 별도의 설치없이 사용하는 커멘드는 없는가
🆀 Swift 코드에서 커멘드를 실행하도록 만들면
Perl 명령을 사용한 파일 이름 변경은 실패하였다. 아래는 GPT 가 제시한 방법이다.
func convertFileNameToNFCUsingPerl(_ url: URL) {
let originalPath = url.path
let directory = url.deletingLastPathComponent().path
let fileName = url.lastPathComponent
let perlCommand = """
/usr/bin/perl -CIO -MUnicode::Normalize -e 'rename shift, shift' "\(originalPath)" "\(directory)/$(/usr/bin/perl -CIO -MUnicode::Normalize -e 'print NFC(shift)' "\(fileName)")"
"""
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/zsh") // 또는 "/bin/bash"
process.arguments = ["-c", perlCommand]
let pipe = Pipe()
process.standardOutput = pipe
process.standardError = pipe
do {
try process.run()
process.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
if let output = String(data: data, encoding: .utf8) {
print(output)
}
if process.terminationStatus == 0 {
print("파일 이름이 NFC로 변환되었습니다.")
} else {
print("perl 명령어 실행 실패")
}
} catch {
print("파일 이름 변환 실패: \(error.localizedDescription)")
}
}
결국 Contact 코드를 분석하여 문제를 해결해보기로 했다.
🆀 https://github.com/namhokim/cocoa_app 에서는 위 문제를 어떻게 해결하고 있지
🆀 https://github.com/namhokim/cocoa_app 를 참고하여 convertFileNameToNFC 함수를 만들면
문제 해결이 되지 않았고 Contact 프로젝트 소스를 확인해보니 perl 정규식이 아닌 단순 mv 명령으로 이름을 변경하는 것으로 확인하여 다시 질문을 했다.
🆀 https://github.com/namhokim/cocoa_app 는 mv 을 사용하여 처리하지 않았나
Perl 을 정규식을 사용하는 점을 제외하면 동일한 방식으로 코드를 제안했지만 문제가 해결되지 않았다. 결국 Contact 의 변환소스에 해당하는 소스를 분석하게 하고 동일하게 코드를 만들라고 하여 문제를 해결 할수 있었다.
🅰
mv 스크립트를 생성하여 실행하는 방식은 정상 동작하고 perl 스크립트 방식에서는 잘못된 문자들로 저장되는 원인을 물어보았으나 이부분에 대한 명확한 답변을 듣지 못했다. 다만 아래와 같은 mv 가 좀더 신뢰성 있게 동작한다는 답변을 얻었다.
아래는 마직막으로 작성된 코드를 실행하는 화면이다.
댓글 없음:
댓글 쓰기