Objective-c iPhone проц кодирует строку? - PullRequest
70 голосов
/ 06 августа 2010

Я хотел бы получить строку в процентах для этих конкретных букв, как это сделать в target-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, ноне работает, результат все тот же, что и исходная строка.Пожалуйста, совет.

Ответы [ 8 ]

141 голосов
/ 06 августа 2010

Я обнаружил, что 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;
}
103 голосов
/ 28 ноября 2013

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-адреса со строкой запроса, поскольку это приведет к добавлению дополнительных процентов к пути.

5 голосов
/ 06 августа 2010
NSString *encodedString = [myString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

Он не заменит вашу строку в строке; он вернет новую строку. Это подразумевается тем фактом, что метод начинается со слова «строка». Это удобный метод для создания нового экземпляра NSString на основе текущей NSString.

Примечание - эта новая строка будет autorelease 'd, поэтому не вызывайте release для нее, когда закончите.

5 голосов
/ 06 августа 2010

NSString stringByAddingPercentEscapesUsingEncoding: выглядит так, как вы ищете.

РЕДАКТИРОВАТЬ : Вот пример использования CFURLCreateStringByAddingPercentEscapes. originalString может быть либо NSString, либо CFStringRef.

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

Обратите внимание, что это не проверено. Вам следует заглянуть на страницу документации , чтобы убедиться, что вы понимаете семантику выделения памяти для CFStringRef, идею беспошлинного моста и т. Д.

Кроме того, я не знаю (вне головы), какой из символов, указанных в аргументе legalURLCharactersToBeEscaped, в любом случае был бы экранирован (из-за недопустимости в URL). Возможно, вы захотите проверить это, хотя, возможно, лучше просто быть в безопасности и напрямую указывать символы, которые вы хотите экранировать.

Я делаю этот ответ в вики сообщества, чтобы люди с большим знанием CoreFoundation могли вносить улучшения.

4 голосов
/ 14 сентября 2016

Следуя стандарту RFC3986, вот что я использую для кодирования компонентов URL:

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

Вывод: email%2Bwith%2Bplus%40example.com

2 голосов
/ 01 сентября 2011

Если вы используете библиотеку ASI HttpRequest в вашей программе target-c, которую я не могу рекомендовать достаточно высоко, то вы можете использовать вспомогательный API encodeURL для его объекта ASIFormDataRequest. К сожалению, API не является статичным, поэтому, возможно, стоит создать расширение, используя его реализацию в вашем проекте.

Код, скопированный прямо из ASIFormDataRequest.m для реализации encodeURL, имеет вид:

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

Как вы можете видеть, это, по сути, оболочка CFURLCreateStringByAddingPercentEscapes, которая заботится обо всех символах, которые должны быть должным образом экранированы.

0 голосов
/ 12 октября 2017

В Swift4:

 var str = "someurl/somecontent"

 let percentEncodedString = str.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
0 голосов
/ 25 февраля 2016

Прежде чем я заметил ответ Роба, который, кажется, работает хорошо и предпочтительнее, поскольку он чище, я продолжил и перенес ответ Дейва на Свифта. Я оставлю это здесь, если кому-то будет интересно:

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
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...