73
67

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iOSでパーセントエンコード(Swift)

Last updated at Posted at 2015-08-04

URLのクエリパラメータや、x-form-urlencodedのbodyで使うためのエスケープ関数を作りたい。

こういうやつ。

"q=" + uriEncode("a")   // => "q=a"
"q=" + uriEncode("a b") // => "q=a%20b"
"q=" + uriEncode("あ")  // => "q=%E3%81%82"

stringByAddingPercentEscapesUsingEncoding

最初に見つけたやつがこれ。

func uriEncode(str: String) -> String {
  return str.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
}

上の仕様だけなら実はこれで成り立つ。しかし、いくつか問題になりそうなやつがある。

"q=" + uriEncode("=") // => "q=="
"q=" + uriEncode("&") // => "q=&"

ツライ。

CFURLCreateStringByAddingPercentEscapes

これじゃ駄目だよということでよく見かけるやつが、 CFURLCreateStringByAddingPercentEscapes を使う方法。

しかし、iOS7からは別の便利なAPIが提供されたそうなので、Swiftだったらそっちを使ったほうが良さそう。

stringByAddingPercentEncodingWithAllowedCharacters

iOS7からのAPIがこれ。

func uriEncode(str: String) -> String {
  return str.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet())!
}

よさそう。

"q=" + uriEncode("=") // => "q=%3D"
"q=" + uriEncode("&") // => "q=%26"

しかし、alphanumericCharacterSet だと上のブログ記事にもあるように、RFC3986的にはエスケープしなくても良いハイフンとかアンダースコアまでエスケープしてしまう。

"q=" + uriEncode("-") // => "q=%2D"
"q=" + uriEncode("_") // => "q=%5F"

これはこれでウェブサーバーは正しく扱ってくれるような気がするけどね。

URLQueryAllowedCharacterSet

NSCharacterSet.URLQueryAllowedCharacterSet というのがあって、一見使えそうに見えるがこれは全然駄目。

// これは駄目なコード
func uriEncode(str: String) -> String {
  return str.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
}
uriEncode("!*'();:@&=+$,/?%#[]-._~ ") // => "!*'();:@&=+$,/?%25%23%5B%5D-._~%20"

特にイコールやアンパサンドがエスケープされていない。

RFC3986準拠

ハイフン、アンダースコア、チルダ、ピリオドをきちんと除外してRFC3986で規定されているような形にするには、たぶん今のところはこうやるしかないのかなと思う。

func uriEncode(str: String) -> String {
  var allowedCharacterSet = NSMutableCharacterSet.alphanumericCharacterSet()
  allowedCharacterSet.addCharactersInString("-._~")
  return str.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacterSet)!
}
uriEncode("!*'();:@&=+$,/?%#[]-._~ ") // => "%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D-._~%20"

まとめ

Swift (iOS7以上)で使うならこれでたぶん十分。

func uriEncode(str: String) -> String {
  return str.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet())!
}

RFC3986に従いたい人はこうする。

func uriEncode(str: String) -> String {
  var allowedCharacterSet = NSMutableCharacterSet.alphanumericCharacterSet()
  allowedCharacterSet.addCharactersInString("-._~")
  return str.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacterSet)!
}
73
67
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
73
67

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?