質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

2406閲覧

日本語のURLエンコードの方法について

mitchi

総合スコア9

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/08/07 08:29

編集2020/08/07 08:56

前提・実現したいこと

Objective-cにて、URLをエンコードしたいのですが、CFURLCreateStringByAddingPercentEscapesがiOS9から非推奨になったことにより置き換えを考えております。いろいろネットを探してみたのですが、うまく変換できません。

'CFURLCreateStringByAddingPercentEscapes' is deprecated: first deprecated in iOS 9.0 - Use [NSString stringByAddingPercentEncodingWithAllowedCharacters:] instead, which always uses the recommended UTF-8 encoding, and which encodes for a specific URL component or subcomponent (since each URL component or subcomponent has different rules for what characters are valid).

今までは、以下のように記載していました。

ObjectiveC

1NSString *str = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)@"https://ドメイン日本語.com/vi/あいう/test?name=かきく&test=漢字", NULL, NULL, kCFStringEncodingUTF8));

結果

https://%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E6%97%A5%E6%9C%AC%E8%AA%9E.com/vi/%E3%81%82%E3%81%84%E3%81%86/test?name=%E3%81%8B%E3%81%8D%E3%81%8F&test=%E6%BC%A2%E5%AD%97

試したこと

以下のサイトのまま文字列を変換したところ、schemeの後の「://」やpathの「/」まで変換されてしまい、うまくいかず。。。
https://qiita.com/totomo/items/370d9aa8b14c4c075a4a

※クエリストリングに対するパーセントエンコーディングと書いてあることは承知の上で試しました。

https%3A%2F%2F%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E6%97%A5%E6%9C%AC%E8%AA%9E.com%2Fvi%2F%E3%81%82%E3%81%84%E3%81%86%2Ftest%3Fname%3D%E3%81%8B%E3%81%8D%E3%81%8F%26test%3D%E6%BC%A2%E5%AD%97

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ご提示のQiitaの先で紹介されているメソッドでやること自体はあっているのですが、URLHostAllowedCharacterSetURLPathAllowedCharacterSet など、URLの各部品ごとに利用可能文字が違ってきますので、丁寧に実装する場合は各部品に対してそれぞれエンコードをかける必要があります。

たとえばこんな感じ...

objectivec

1// NSURL+IDN.h 2 3@interface NSURL (IDN) 4 5+ (NSURL * __nullable) URLWithIDNURLString:(NSString * __nonnull)str; 6 7@end

objectivec

1// NSURL+IDN.m 2 3@implementation NSURL (IDN) 4 5+ (NSURL * __nullable) URLWithIDNURLString:(NSString * __nonnull)str { 6 // <scheme>://<user>:<password>@<host>:<port>/<path>?<query>#<fragment> 7 8 // 与えられた文字列を :// でsplitする。[0]が <scheme> 9 NSMutableArray<NSString*> *components = [str componentsSeparatedByString:@"://"].mutableCopy; 10 if(components.count <= 1) return nil; 11 NSMutableString *encodedStr = [components[0] stringByAppendingString:@"://"].mutableCopy; 12 13 // components[1] 以降をNSStringに戻して、今度は / でsplitする。[0]を host として保持する 14 [components removeObjectAtIndex:0]; 15 components = [[components componentsJoinedByString:@"://"] componentsSeparatedByString:@"/"].mutableCopy; 16 NSString *host = components[0]; 17 18 // <user>:<password> を持っているかチェックする 19 NSArray<NSString*> *hostComponents = [host componentsSeparatedByString:@"@"]; 20 NSArray<NSString*> *userComponents = [hostComponents[0] componentsSeparatedByString:@":"]; 21 if(hostComponents.count > 1 && userComponents.count > 1) { 22 [encodedStr appendFormat: 23 @"%@:%@@", 24 [userComponents[0] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLUserAllowedCharacterSet], 25 [userComponents[1] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPasswordAllowedCharacterSet] 26 ]; 27 host = [host substringFromIndex:hostComponents[0].length + 1]; 28 } 29 30 // <port> を持っているかチェックする。ある場合は portComponentsの最後の要素が <port> で、その手前はすべて <host> になる 31 NSMutableArray<NSString*> *portComponents = [host componentsSeparatedByString:@":"].mutableCopy; 32 if(portComponents.count == 1) { 33 // <port> がない場合 34 [encodedStr appendString:[host stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]]; 35 } else { 36 // <port> がある場合 37 NSString *port = portComponents[portComponents.count - 1]; 38 [portComponents removeObjectAtIndex:portComponents.count - 1]; 39 [encodedStr appendFormat:@"%@:%@", [[portComponents componentsJoinedByString:@":"] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet], port]; 40 } 41 42 // components[1] 以降をNSStringに戻して、今度は ? でsplitする。[0]が <path> 43 [components removeObjectAtIndex:0]; 44 components = [[components componentsJoinedByString:@"/"] componentsSeparatedByString:@"?"].mutableCopy; 45 [encodedStr appendFormat:@"/%@", [components[0] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet]]; 46 47 // components[1] 以降をNSStringに戻して、今度は # でsplitする。[0]が <query>, [1]以降が <fragment> 48 [components removeObjectAtIndex:0]; 49 components = [[components componentsJoinedByString:@"?"] componentsSeparatedByString:@"#"].mutableCopy; 50 if(components[0].length) { 51 [encodedStr appendFormat:@"?%@", [components[0] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]]; 52 } 53 if(components.count > 1) { 54 [components removeObjectAtIndex:0]; 55 [encodedStr appendFormat:@"#%@", [[components componentsJoinedByString:@"#"] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLFragmentAllowedCharacterSet]]; 56 } 57 58 return [NSURL URLWithString:encodedStr]; 59} 60 61@end

objective

1// 使い方 2#import "NSURL+IDN.h" 3- (void) nanikashiraNoMethod { 4 [@[ 5 @"https://ドメイン日本語.com/vi/あいう/test?name=かきく&test=漢字", 6 @"https://ユーザー:パスワード@ドメイン日本語.com/vi/あいう/test?name=かきく&test=漢字", 7 @"https://ドメイン日本語.com:8000/vi/あいう/test?name=かきく&test=漢字#項1タイトル", 8 @"https://ユーザー:パスワード@ドメイン日本語.com:8000/vi/あいう/test?name=かきく&test=漢字#項1タイトル", 9 ] enumerateObjectsUsingBlock:^(NSString * _Nonnull str, NSUInteger idx, BOOL * _Nonnull stop) { 10 NSString *encodedStr = [NSURL URLWithIDNURLString:str].absoluteString; 11 NSLog(@"%@", encodedStr); 12 }]; 13 /* 14 https://%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E6%97%A5%E6%9C%AC%E8%AA%9E.com/vi/%E3%81%82%E3%81%84%E3%81%86/test?name=%E3%81%8B%E3%81%8D%E3%81%8F&test=%E6%BC%A2%E5%AD%97 15 https://%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC:%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89@%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E6%97%A5%E6%9C%AC%E8%AA%9E.com/vi/%E3%81%82%E3%81%84%E3%81%86/test?name=%E3%81%8B%E3%81%8D%E3%81%8F&test=%E6%BC%A2%E5%AD%97 16 https://%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E6%97%A5%E6%9C%AC%E8%AA%9E.com:8000/vi/%E3%81%82%E3%81%84%E3%81%86/test?name=%E3%81%8B%E3%81%8D%E3%81%8F&test=%E6%BC%A2%E5%AD%97#%E9%A0%851%E3%82%BF%E3%82%A4%E3%83%88%E3%83%AB 17 https://%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC:%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89@%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E6%97%A5%E6%9C%AC%E8%AA%9E.com:8000/vi/%E3%81%82%E3%81%84%E3%81%86/test?name=%E3%81%8B%E3%81%8D%E3%81%8F&test=%E6%BC%A2%E5%AD%97#%E9%A0%851%E3%82%BF%E3%82%A4%E3%83%88%E3%83%AB 18 */ 19}

※丁寧に実装しなくてもいい場合とは、決まったドメインのURLしか渡ってこないことが仕様上確定している場合などです。

投稿2020/08/10 17:46

thyda.eiqau

総合スコア2982

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mitchi

2020/08/11 02:13

ありがとうございます! 私自身でも調べていたのですが、やはりそうやるしかなさそうですね。。。 後、ドメイン部分に関してはPunycodeという考え方(?)もあるそうなので、組み合わせて対応したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問