Program Club

Objective-c iPhone 백분율은 문자열을 인코딩합니까?

proclub 2020. 10. 30. 21:17
반응형

Objective-c iPhone 백분율은 문자열을 인코딩합니까?


이 특정 문자에 대한 백분율 인코딩 문자열을 얻고 싶습니다. Objective-c에서 어떻게 수행합니까?

Reserved characters after percent-encoding
!   *   '   (   )   ;   :   @   &   =   +   $   ,   /   ?   #   [   ]
%21 %2A %27 %28 %29 %3B %3A %40 %26 %3D %2B %24 %2C %2F %3F %23 %5B %5D

백분율 인코딩 위키

이 문자열로 테스트하고 작동하는지 확인하십시오.

myURL = @"someurl/somecontent"

문자열이 다음과 같이 보이기를 바랍니다.

myEncodedURL = @"someurl%2Fsomecontent"

stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding이미 시도했지만 작동하지 않으며 결과는 여전히 원래 문자열과 동일합니다. 조언 부탁드립니다.


stringByAddingPercentEscapesUsingEncoding:둘 다 CFURLCreateStringByAddingPercentEscapes()부적절하다는 것을 발견했습니다 . NSString방법은 꽤 많은 문자를 놓치고 CF 기능을 사용하면 이스케이프하려는 특정 문자 만 지정할 수 있습니다. 적절한 사양은 작은 집합을 제외한 모든 문자를 이스케이프하는 것입니다.

이 문제를 해결하기 위해 NSString문자열을 올바르게 인코딩 하는 범주 메서드를 만들었습니다 . 제외 [a-zA-Z0-9.-_~]하고 모든 것을 퍼센트 인코딩 하고 공백도 +( 이 사양 에 따라) 인코딩합니다 . 또한 인코딩 유니 코드 문자를 올바르게 처리합니다.

- (NSString *) URLEncodedString_ch {
    NSMutableString * output = [NSMutableString string];
    const unsigned char * source = (const unsigned char *)[self UTF8String];
    int sourceLen = strlen((const char *)source);
    for (int i = 0; i < sourceLen; ++i) {
        const unsigned char thisChar = source[i];
        if (thisChar == ' '){
            [output appendString:@"+"];
        } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' || 
                   (thisChar >= 'a' && thisChar <= 'z') ||
                   (thisChar >= 'A' && thisChar <= 'Z') ||
                   (thisChar >= '0' && thisChar <= '9')) {
            [output appendFormat:@"%c", thisChar];
        } else {
            [output appendFormat:@"%%%02X", thisChar];
        }
    }
    return output;
}

이제 iOS 7 SDK에는 stringByAddingPercentEscapesUsingEncoding허용 된 특정 문자를 제외한 모든 문자를 이스케이프하도록 지정할 수 있는 더 나은 대안이 있습니다. URL을 부분적으로 구축하는 경우 잘 작동합니다.

NSString * unescapedQuery = [[NSString alloc] initWithFormat:@"?myparam=%d", numericParamValue];
NSString * escapedQuery = [unescapedQuery stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString * urlString = [[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext%@", escapedQuery];

URL의 다른 부분이 변수가되는 경우는 드물지만 NSURLUtilities 범주에도 해당 항목에 대한 상수가 있습니다.

[NSCharacterSet URLHostAllowedCharacterSet]
[NSCharacterSet URLUserAllowedCharacterSet]
[NSCharacterSet URLPasswordAllowedCharacterSet]
[NSCharacterSet URLPathAllowedCharacterSet]
[NSCharacterSet URLFragmentAllowedCharacterSet]

[NSCharacterSet URLQueryAllowedCharacterSet]포함 모든 URL의 쿼리 부분에 허용되는 문자의합니다 (로 시작하는 부분 ?과 전에 #을 포함하여 조각에있는 경우) ?&또는 =매개 변수 이름과 값을 구분하는 데 사용되는 문자를. 영숫자 값이있는 쿼리 매개 변수의 경우 이러한 문자가 쿼리 문자열을 작성하는 데 사용되는 변수 값에 포함될 수 있습니다. 이 경우 쿼리 문자열의 부분 을 이스케이프 처리해야하므로 약간의 작업이 더 필요합니다.

NSMutableCharacterSet * URLQueryPartAllowedCharacterSet; // possibly defined in class extension ...

// ... and built in init or on first use
URLQueryPartAllowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[URLQueryPartAllowedCharacterSet removeCharactersInString:@"&+=?"]; // %26, %3D, %3F

// then escape variables in the URL, such as values in the query and any fragment:
NSString * escapedValue = [anUnescapedValue stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet];
NSString * escapedFrag = [anUnescapedFrag stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
NSString * urlString = [[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext?myparam=%@#%@", escapedValue, escapedFrag];
NSURL * url = [[NSURL alloc] initWithString:urlString];

unescapedValue심지어 콜백 또는 리디렉션에 대한 같은 전체 URL, 수 :

NSString * escapedCallbackParamValue = [anAlreadyEscapedCallbackURL stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet];
NSURL * callbackURL = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext?callback=%@", escapedCallbackParamValue]];

참고 : NSURL initWithScheme:(NSString *)scheme host:(NSString *)host path:(NSString *)path쿼리 문자열이있는 URL에는 경로에 더 많은 이스케이프 비율이 추가되므로 사용하지 마십시오 .


NSString *encodedString = [myString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

인라인 문자열을 대체하지 않습니다. 새 문자열을 반환합니다. 이는 메서드가 "문자열"이라는 단어로 시작한다는 사실에 의해 암시됩니다. 현재 NSString을 기반으로 NSString의 새 인스턴스를 인스턴스화하는 편리한 방법입니다.

참고-새 문자열은 autorelease'd이므로 작업이 끝나면 release를 호출하지 마십시오.


NSString의 stringByAddingPercentEscapesUsingEncoding : 당신이 추구하는 것처럼 보입니다.

편집 : 여기에 CFURLCreateStringByAddingPercentEscapes대신 사용하는 예가 있습니다. originalString할 수 있습니다 어느 쪽 NSStringCFStringRef.

CFStringRef newString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, originalString, NULL, CFSTR("!*'();:@&=+@,/?#[]"), kCFStringEncodingUTF8);

Please note that this is untested. You should have a look at the documentation page to make sure you understand the memory allocation semantics for CFStringRef, the idea of toll-free bridging, and so on.

Also, I don't know (off the top of my head) which of the characters specified in the legalURLCharactersToBeEscaped argument would have been escaped anyway (due to being illegal in URLs). You may want to check this, although it's perhaps better just to be on the safe side and directly specify the characters you want escaped.

I'm making this answer a community wiki so that people with more knowledge about CoreFoundation can make improvements.


Following the RFC3986 standard, here is what I'm using for encoding URL components:

// https://tools.ietf.org/html/rfc3986#section-2.2
let rfc3986Reserved = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?#[]")
let encoded = "email+with+plus@example.com".stringByAddingPercentEncodingWithAllowedCharacters(rfc3986Reserved.invertedSet)

Output: email%2Bwith%2Bplus%40example.com


If you are using ASI HttpRequest library in your objective-c program, which I cannot recommend highly enough, then you can use the "encodeURL" helper API on its ASIFormDataRequest object. Unfortunately, the API is not static so maybe worth creating an extension using its implementation in your project.

The code, copied straight from the ASIFormDataRequest.m for encodeURL implementation, is:

- (NSString*)encodeURL:(NSString *)string
{
    NSString *newString = NSMakeCollectable([(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding])) autorelease]);
    if (newString) {
        return newString;
    }
    return @"";
}

As you can see, it is essentially a wrapper around CFURLCreateStringByAddingPercentEscapes that takes care of all the characters that should be properly escaped.


Before I noticed Rob's answer, which appears to work well and is preferred as it's cleaner, I went ahead and ported Dave's answer to Swift. I'll leave it here in case anyone is interested:

public extension String {

    // For performance, I've replaced the char constants with integers, as char constants don't work in Swift.

    var URLEncodedValue: String {
        let output = NSMutableString()
        guard let source = self.cStringUsingEncoding(NSUTF8StringEncoding) else {
            return self
        }
        let sourceLen = source.count

        var i = 0
        while i < sourceLen - 1 {
            let thisChar = source[i]
            if thisChar == 32 {
                output.appendString("+")
            } else if thisChar == 46 || thisChar == 45 || thisChar == 95 || thisChar == 126 ||
                (thisChar >= 97 && thisChar <= 122) ||
                (thisChar >= 65 && thisChar <= 90) ||
                (thisChar >= 48 && thisChar <= 57) {
                    output.appendFormat("%c", thisChar)
            } else {
                output.appendFormat("%%%02X", thisChar)
            }

            i++
        }

        return output as String
    }
}

In Swift4:

 var str = "someurl/somecontent"

 let percentEncodedString = str.addingPercentEncoding(withAllowedCharacters: .alphanumerics)

참고URL : https://stackoverflow.com/questions/3423545/objective-c-iphone-percent-encode-a-string

반응형