Swift3でSJISを使ったURLエンコードをしたい

投稿者: Anonymous

Swift3にて、Shift-JISでURLをエンコードする必要が出てきたのですが、
String.addingPercentEscapesが非推奨になっており、代わりにString.addingPercentEncodingを使用するように警告が出てしまいました。

いろいろ調べてみたのですが、String.addingPercentEscapesを使用せずにShift-JISでURLエンコードを行う方法が分からなかったため、ご教授いただきたいです。

解決

本来なら、アプリ側をSJISに対応させるのではなく、サーバー側をUTF-8に対応させるのが筋だと思うのですが…。

AppleがSJIS対応のURLエンコード機能をiOSやSwiftの標準ライブラリーに再度付け加える可能性は極めて低いでしょうから、全部自前で処理してやる必要があります。

例えばこんな感じになるでしょう。

extension CharacterSet {
    static let rfc3986Unreserved = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~")
}

extension String.Encoding {
    static let windows31j = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.dosJapanese.rawValue)))
}

extension String {
    func addingPercentEncoding(withAllowedCharacters characterSet: CharacterSet, using encoding: String.Encoding) -> String {
        let stringData = self.data(using: encoding, allowLossyConversion: true) ?? Data()
        let percentEscaped = stringData.map {byte->String in
            if characterSet.contains(UnicodeScalar(byte)) {
                return String(UnicodeScalar(byte))
            } else if byte == UInt8(ascii: " ") {
                return "+"
            } else {
                return String(format: "%%%02X", byte)
            }
        }.joined()
        return percentEscaped
    }

    var sjisPercentEncoded: String {
        return self.addingPercentEncoding(withAllowedCharacters: .rfc3986Unreserved,  using: .windows31j)
    }
}

let escaped = "今時SJISのシステムなんて…".sjisPercentEncoded
print(escaped) //->%8D%A1%8E%9ESJIS%82%CC%83V%83X%83e%83%80%82%C8%82%F1%82%C4%81c

通常SJISと名乗っているシステムは、Windows拡張文字も受け取れることが多いので、上記ではString.Encoding.shiftJISではなく、Windows-31J相当のエンコーディングを使用しています。

実際にこれがデコードできるかどうかは、サーバーサイドが、どうパーセントエンコーディングを処理しているかによりますので、果たして上記のコードが無事に動くかどうかはなんとも言えません。

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *