2010/10/06

NSURLとURLのエスケープについて

以前の記事「iOSで独自カスタムURLスキームを設定する方法について」では、カスタムURLスキームを受け入れるアプリケーションはapplication:handleOpenURL:で与えられたNSURLオブジェクトに基づいて処理を行えばよいと述べました。

この記事では与えられた文字列に対するNSURLのアクセスメソッドの返す値や、URL向けの文字列エスケープ (%エスケープ; 文字列を%xxの形式に変換する) の方法について紹介します。

NSURLのアクセスメソッドについて

カスタムURLスキームの書式をRFC 1808に従うようにするならば、次のようになります。

  <scheme>://<host></path>;< parameterString>?<query>#<fragment>

もっとも、これにこだわる必要はなく好きに実装してもよいようです。そこで、規約に違反している文字列でNSURLのschemeなどのメソッドがどのような値を返すのかを調べてみました。URLWithString:で与えた文字列をそれぞれのメソッドで表示させた結果を以下に示します。なお、結果がnull以外になった場合のみを示しています。

なお、結果(6)でも示しますが、コロン(:)もなしで「mySampleApp」のみの場合には、Safari上ではhttp://mySampleApp/と解釈されますので、最低限コロンは付けたほうがよいと思います。

(1) mySampleApp://www.example.com/xxx;r=xxx?q=yyy#section
RFC 1808の書式に完全に従った場合。
schememySampleApp
hostwww.example.com
path/xxx
parameterStringr=xxx
queryq=yyy
fragmentsection

(2) mySampleApp:///xxx?q=yyy
これはホスト部が空だと見なされているようです。
schememySampleApp
path/xxx
queryq=yyy

(3) mySampleApp://xxx?q=yyy
これはパス部が空だと見なされているようです。
schememySampleApp
hostxxx
path
queryq=yyy

(4) mySampleApp:/xxx?q=yyy
schememySampleApp
path/xxx
queryq=yyy

(5) mySampleApp:xxx?q=yyy
スキーマ以外nullになってしまうので、absoluteStringなどを使って切り出すしかないようです。
schememySampleApp

(6) mySampleApp
pathmySampleApp

以上からわかるように、「://」を含めない場合は意図しない結果になるかもしれませんので、最悪absoluteStringなどを使って切り出したほうがよいかもしれません。

なお、RFC 1808にこだわる必要はないと述べましたが、これらのセパレータになる文字を2回使う (例えば、mySampleApp://foobar?ddd#yyy#qqq) とURLWithString:がnullを返すようになります (リファレンスに書いてありますが、これらの文字を使うときは%エスケープをする必要があります)。

URL向けの文字列エスケープ (%エスケープ)

NSStringには文字列を%xxの形式に変換するメソッドと逆変換するメソッドstringByAddingPercentEscapesUsingEncoding:stringByReplacingPercentEscapesUsingEncoding:が用意されています。これらのメソッドでは引数で変換後のエンコーディングを指定します。

アスキーコード内でstringByAddingPercentEscapesUsingEncoding:で%エスケープされる文字列は次の通りです。RFC 1808でセパレータになっている ; や ? などは含まれていませんので注意が必要です。

hex
01〜1f(制御コード)
20(スペース)
22"
23#
25%
3c<
3e>
5b[
5c\
5d]
5e^
60`
7b{
7c|
7d}
7f

なお、より細かい制御にはCore Foundationの2つの関数を利用することができます。

  • CFURLCreateStringByAddingPercentEscapes の第3引数にはデフォルトでは変換されるがしたくない文字を、第4引数にはデフォルトでは変換されないがしたい文字を、それぞれ文字列で指定します。 CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,str, null, null, encoding)と同等

  • CFURLCreateStringByReplacingPercentEscapes 第3引数には元に戻したくない文字を指定します (nullならどの文字も変換しない、""なら全て変換する)。 CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, str, CFSTR(""))と同等

また、元からエスケープされている文字列をエスケープするには一旦元の文字列に戻して再び変換を行うようにします。サンプルコードを次に示します。

NSString* s = @"http://www.bing.com/search?q=safx-dev%20ios%20iphone";
CFStringRef p = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(
                  kCFAllocatorDefault, (CFStringRef) s,
                  CFSTR(""), kCFStringEncodingUTF8);
CFStringRef d = CFURLCreateStringByAddingPercentEscapes(
                  kCFAllocatorDefault, p,
                  NULL, CFSTR("/:;?"), kCFStringEncodingUTF8);

まとめ

与えられた文字列に対するNSURLのアクセスメソッドの返す値や、URL向けの文字列エスケープ (%エスケープ) の方法について紹介しました。

関連項目

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。