Swift에서 Unicde 정규화 문제 속편: HFS+와 일치성

9574 단어 Swift
저번 보도의 속편.

HFS+의 Modified NFC


애플은 OS X에 파일 시스템HFS+을 적용해 원칙적으로 파일 이름을 NFD로 분해해 보관하고 있다.

두 가지 "가"가 분해 형식으로 통일되었다


예를 들어 사용자가 파일 이름が.txt("가"가"가 U+304C의 한 문자)으로 파일을 저장하더라도 파일 시스템에서が.txt("가"가"가 U+304B U+3099의 합성 문자)로 저장한다.
실제로 파일을 が.txt("가"가"가 U+304C의 한 문자)로 저장한 후 Finder가 파일 이름 변경 모드에 들어가"가"라는 문자를 복사하면 U+304C가 아닌 U+304BU+3099 두 문자가 복사된 것을 확인할 수 있다.
→ 또는 (U+304B)+ 결합용 탁점(U+3099) 복제

CJK 호환 한자의 Modified NFC를 바꾸지 않음


이 정규화 형식은 언뜻 보면 보통 NFC인 것 같다.하지만 단순히 NFC로 분해하면 한자 달라지는 문제가 생긴다.
'new.txt'를 저장해도'신.txt'가 돼 실제 응용에 불편을 겪는다는 것이다.
이에 따라 애플은 HFS+ 정규화에서 유니코드 표준화 규격을 따르지 않고 CJK 호환 한자 등 정규화된 문자를 제외하고 독자적으로 정규화했다.이를 Modified NFC(정식 이름은 아니지만 따른다NAOI 권장 사항라고 합니다.
Modified NFC의 규격물야 선생의 해설에 관해서는 매우 통속적이고 알기 쉽게 총결하였다.
이 Modified NFC는 CJK 겸용 한자를 교체할 수 없고 두 가지'가오'가 통일되어 우리 일본인들에게 편리한 정규화 방식이다.그러나 애플이 Unicde 기술위원회에 이 건의를 했을 때부결되다는 이렇다.그 결과 이 모델ified NFC는 지금까지 표준화되지 않은 애플만의 정규화 형태로 바뀌었다.

Swift 문자열의 일관성


한편, 스위프트 문자열을 비교할 때 내부에서 발동하는 정규화는 일반적인 NFC나 NFC(어느 것인지 알 수 없음)로 CJK 호환 한자를 교체했다.
파일 시스템에서는 Modified NFC를 사용하지만 프로그래밍 언어에서는 NFD/NFC를 기본적으로 사용해 통합성이 좋은지 걱정된다.
하지만
  • 스위프트 스트링의 NFC/NFC 귀일화는 비교 문자열 사이의 시간에만 발동되며 그 외에는 발동하지 않는다.
  • 파일의 존재 판정 등의 정규화는 파일 시스템 측이 Modified NFC를 통해 수행한다.
  • 이런 규격이어서 일시적으로 일치성을 얻었다.
    다음은 코드로 확인해 보겠습니다.
    // テキストファイルの内容を読み込んで表示する関数
    func printFile(filename : String) {
        println(NSString(contentsOfFile: filename, encoding: NSUTF8StringEncoding, error: nil)!)
    }
    
    let gaC = "\u{304C}.txt" // 結合形の「が」
    let gaD = "\u{304B}\u{3099}.txt" // 分解形の「が」
    let  = "神.txt" // U+795E
    let  = "神.txt" // U+FA19
    
    let manager = NSFileManager.defaultManager()
    
    if manager.fileExistsAtPath(gaC) {
        println("結合形でヒットしました")
        printFile(gaC) // が.txt の内容を表示
    }
    if manager.fileExistsAtPath(gaD) {
        println("分解形でヒットしました")
        printFile(gaD) // が.txt の内容を表示
    }
    
     ==  // => true; 文字列としては同一と判定される
    
    if manager.fileExistsAtPath() {
        println("神は存在します")
        printFile() // 神.txt の内容を表示
    } else {
        println("神は存在しません")
    }
    
    if manager.fileExistsAtPath() {
        println("神は存在します")
        printFile() // 神.txt の内容を表示
    } else {
        println("神は存在しません")
    }
    
    이 코드를 실행하면 파일 시스템은 어떤 "접근"을 사용하든 분할 형식으로 통일적으로 해석되고, 파일 시스템에 が.txt 존재하면 fileExistsAtPath(gaC)fileExistsAtPath(gaD) 모두 진실로 판정된다.또한 동일한 파일が.txt을 읽을 수 있습니다.
    반면 후반부神.txt神.txt에서는 스위프트에서 문자열이 동일하다고 판정되지만 파일의 판정과 내용 읽기 측면에서는 별도로 처리된다.
    예를 들어 파일 시스템에 神.txt神.txt가 존재하지 않으면 상기 코드를 실행할 때
    神は存在しません
    神は存在します
    
    대화 상자.
    따라서 HFS+에 접근할 때 프로그래머가 기대한 결과를 먼저 얻었다고 할 수 있다.

    잠재적인 버그의 온상이 될 수 있을까요?


    그러나 문자열 비교에 포함된 정규화 현상은 잠재적인 오류를 초래할 수 있다.
    예를 들어, 아마도 심심한 예일 것이다. 다음 코드.
    let adminName = "神"
    
    // テキストファイルの内容を読み込んで表示する関数
    func printFile(filename : String) {
        println(NSString(contentsOfFile: filename, encoding: NSUTF8StringEncoding, error: nil)!)
    }
    
    func login(userName : String) {
        if userName == adminName {
            println("あなたは管理者ユーザです")
            printFile(adminName + ".txt")
        } else {
            println("あなたは一般ユーザです")
            printFile(userName + ".txt")
        }
    }
    
    login("神")
    
    네오 로그인으로 읽기神.txt할 예정이지만 파일 시스템의 다른 파일神.txt은 읽힌다.
    이것은 정말 무섭다."Swift의 문자열은 비교적 무섭다"는 의식이 필요하다.

    좋은 웹페이지 즐겨찾기