Help us understand the problem. What is going on with this article?

Swiftで「 / 」が入った文字列を持つStructをJSON化して送ろうとした際に2重にエスケープされてしまって困った

More than 1 year has passed since last update.

読む前に

以下の内容ですが、私のJSONに対する現状の知識不足が原因でした。
JSONのエスケープ対象として/が含まれており、JSONとして出力した際に\/となるのは正しい挙動となります。
2重エスケープされていたのは" {"data" : "aa\\/bbb"}"""で囲われていたのが原因でした。
私と同様に上記を把握しておらず、解決方法を探した方が見つけられるように本記事は削除せずそのまま残すことにします。

はじめに

EncodableのStructをencodeしdataに変換、 String(data: Data, encoding: String.Encoding)を使って文字列にするといった処理を行っていました。
その際にEscape周りで意外な挙動があったので記載します。

検証環境

以下の環境を使用しています。

  • macOS High Sierra Version 10.14.2
  • Xcode Version 10.1.0
  • Swift Version 4.2

事象

struct Debug: Codable {
    let date = "[aaa/bbb]" // / が含まれるように文字列を定義
}

let encoder = JSONEncoder()
let data = try! encoder.encode(Debug())
let string = String(data: data, encoding: .utf8) // DataからJSON文字列生成
print(string)

上記のコードを実行した際に、{"date":"[aaa/bbb]"}の文字列が取得できることを期待しました。
しかし実際に取得できた文字列は{"date":"[aaa\/bbb]"}になります。
タイトルの通り /が2重にエスケープされてしまい \\/となった結果、文字列化した際に\/となり\が余分につくという事象が発生しました。
stringをForced Unwrapしなかった場合は Optional("{\"date\":\"[aaa\\/bbb]\"}")となり、2重にエスケープされていることがわかります。

対応

以下のことを試しました。

  • /\u{002F}に変換する。(\u{002F}/のUnicodeコード表現です)
  • CodableのJSONEncoderではなくJSONSerialization経由で文字列化する
  • String(data: Data, eocoding: String.Encoding)のencodingパラメータを変える

ただ、上記の方法ではどれも解決に至りませんでした。

最終的にとった方法は以下になります。\\//に置き換えました。
これで{"date":"[aaa/bbb]"}という期待したとおりの文字列を取得することができました。

let string = String(data: data, encoding: .utf8)?.replacingOccurrences(of: "\\/", with: "/")

最後に

正直にいって本記事の対応はあまり良いと思えません。このあたり知見がある方や、このようにしたほうがいいのではないか等ありましたらコメントいただけますと幸いです。

iganin
iOSをメインにアプリケーションの開発を担当しています。現在はSwift, iOS, Kotlin, AWSに主な興味があります。物理と数学が好きです。
https://iganin.hatenablog.com
engineerlife
技術力をベースに人生を謳歌する人たちのコミュニティです。
https://community.camp-fire.jp/projects/view/280040
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした