ご提示のQiitaの先で紹介されているメソッドでやること自体はあっているのですが、URLHostAllowedCharacterSet
や URLPathAllowedCharacterSet
など、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/11 02:13