Заміна для stringByAddingPercentEscapesUsingEncoding в ios9?


112

У iOS8 та попередніх версіях я можу використовувати:

NSString *str = ...; // some URL
NSString *result = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

в iOS9 stringByAddingPercentEscapesUsingEncodingбуло замінено на stringByAddingPercentEncodingWithAllowedCharacters:

NSString *str = ...; // some URL
NSCharacterSet *set = ???; // where to find set for NSUTF8StringEncoding?
NSString *result = [str stringByAddingPercentEncodingWithAllowedCharacters:set];

і моє запитання: де знайти потрібне NSCharacterSet( NSUTF8StringEncoding) для правильної заміни stringByAddingPercentEscapesUsingEncoding?

Відповіді:


131

У повідомленні про припинення роботи (моє наголос):

Замість цього використовуйте stringByAddingPercentEncodingWithAllowedCharacters (_ :), який завжди використовує рекомендоване кодування UTF-8 і кодує певний компонент або підкомпонент URL, оскільки кожен компонент URL або підкомпонент має різні правила щодо дійсних символів.

Тож вам потрібно лише надати адекватний NSCharacterSetаргумент. На щастя, для URL-адрес існує дуже зручний метод класу, URLHostAllowedCharacterSetякий можна використовувати так:

let encodedHost = unencodedHost.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())

Оновлення для Swift 3 - метод стає статичною властивістю urlHostAllowed:

let encodedHost = unencodedHost.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)

Однак майте на увазі, що:

Цей метод призначений для відсоткового кодування компонента URL або рядка підкомпонента, а не цілого рядка URL.


6
Крім того, я настійно пропоную використовувати NSURLComponents, яке може обробляти відсоткове кодування для вас.
Антоніо Фавата

1
Будь-які пропозиції щодо використання для всього рядка URL-адреси?
Майстерність M2

1
@ SkillM2 Я думаю NSURLComponents(кожен компонент у відсотках кодується відповідним NSCharacterSet) - це правильний шлях.
Антоніо Фавата

2
Ви ніколи, ніколи, ніколи не намагайтеся кодувати цілий рядок URL. Це може спричинити несподівані помилки, а в деяких випадках - і безпечні отвори. Єдиний гарантований правильний спосіб кодування URL - це робити це по черзі.
dgatwood

Чудово. Велике спасибі, приятелю!
Феліпе

100

Для Objective-C:

NSString *str = ...; // some URL
NSCharacterSet *set = [NSCharacterSet URLHostAllowedCharacterSet]; 
NSString *result = [str stringByAddingPercentEncodingWithAllowedCharacters:set];

де знайти набір для NSUTF8StringEncoding?

Існують заздалегідь задані набори символів для шести компонентів URL та підкомпонентів, які дозволяють кодувати відсотки. Ці набори символів передаються до -stringByAddingPercentEncodingWithAllowedCharacters:.

 // Predefined character sets for the six URL components and subcomponents which allow percent encoding. These character sets are passed to -stringByAddingPercentEncodingWithAllowedCharacters:.
@interface NSCharacterSet (NSURLUtilities)
+ (NSCharacterSet *)URLUserAllowedCharacterSet;
+ (NSCharacterSet *)URLPasswordAllowedCharacterSet;
+ (NSCharacterSet *)URLHostAllowedCharacterSet;
+ (NSCharacterSet *)URLPathAllowedCharacterSet;
+ (NSCharacterSet *)URLQueryAllowedCharacterSet;
+ (NSCharacterSet *)URLFragmentAllowedCharacterSet;
@end

У повідомленні про припинення роботи (моє наголос):

Замість цього використовуйте stringByAddingPercentEncodingWithAllowedCharacters (_ :), який завжди використовує рекомендоване кодування UTF-8 і кодує певний компонент або підкомпонент URL, оскільки кожен компонент URL або підкомпонент має різні правила щодо дійсних символів.

Тож вам потрібно лише надати адекватний NSCharacterSetаргумент. На щастя, для URL-адрес існує дуже зручний метод класу, URLHostAllowedCharacterSetякий можна використовувати так:

NSCharacterSet *set = [NSCharacterSet URLHostAllowedCharacterSet]; 

Однак майте на увазі, що:

Цей метод призначений для відсоткового кодування компонента URL або рядка підкомпонента, а не цілого рядка URL.


4
Я люблю, коли Apple полегшує життя. Спасибі яблуко.
Качка

5
Що означає "Цей метод призначений для відсоткового кодування URL-компонента або рядка підкомпонента, а не цілого рядка URL-адреси". ?
GeneCode

4
URLHostAllowedCharacterSet давав помилку "Непідтримувана URL-адреса", я використовував URLFragmentAllowedCharacterSet та його добре працює.
anoop4real

1
це не працює з +, він не кодує його, і його замінить пробіл на стороні сервера, як за специфікацією.
Торге

45

URLHostAllowedCharacterSetце НЕ ПРАЦЮЄ ДЛЯ МЕНЕ. Я використовую URLFragmentAllowedCharacterSetзамість цього.

МЕТА -С

NSCharacterSet *set = [NSCharacterSet URLFragmentAllowedCharacterSet];
NSString * encodedString = [@"url string" stringByAddingPercentEncodingWithAllowedCharacters:set];

SWIFT - 4

"url string".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)

Наступні корисні (перевернуті) набори символів:

URLFragmentAllowedCharacterSet  "#%<>[\]^`{|}
URLHostAllowedCharacterSet      "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet  "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet      "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet     "#%<>[\]^`{|}
URLUserAllowedCharacterSet      "#%/:<>?@[\]^`

Дякую і те саме вам
Арпіт Б Парех

Варто зазначити, що жоден із цих наборів не включає +. Так що знаки плюс у рядку будуть зіпсовані, якщо передаються в параметрах запиту - трактуються як пробіл `` на стороні сервера.
Asmo Soinio

21

Ціль-С

цей код працює для мене:

urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];

4

Swift 2.2:

extension String {
 func encodeUTF8() -> String? {
//If I can create an NSURL out of the string nothing is wrong with it
if let _ = NSURL(string: self) {

    return self
}

//Get the last component from the string this will return subSequence
let optionalLastComponent = self.characters.split { $0 == "/" }.last


if let lastComponent = optionalLastComponent {

    //Get the string from the sub sequence by mapping the characters to [String] then reduce the array to String
    let lastComponentAsString = lastComponent.map { String($0) }.reduce("", combine: +)


    //Get the range of the last component
    if let rangeOfLastComponent = self.rangeOfString(lastComponentAsString) {
        //Get the string without its last component
        let stringWithoutLastComponent = self.substringToIndex(rangeOfLastComponent.startIndex)


        //Encode the last component
        if let lastComponentEncoded = lastComponentAsString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet()) {


        //Finally append the original string (without its last component) to the encoded part (encoded last component)
        let encodedString = stringWithoutLastComponent + lastComponentEncoded

            //Return the string (original string/encoded string)
            return encodedString
        }
    }
}

return nil;
}
}

2

Для Swift 3.0

Ви можете використовувати urlHostAllowedcharacterSet.

/// Повертає набір символів для символів, дозволених у підкомпоненті URL-адреси хоста.

public static var urlHostAllowed: CharacterSet { get }

WebserviceCalls.getParamValueStringForURLFromDictionary(settingsDict as! Dictionary<String, AnyObject>).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed)

1

Що означає "Цей метод призначений для відсоткового кодування URL-компонента або рядка підкомпонента, а не цілого рядка URL-адреси". ? - GeneCode 1 вересня 1616 о 8:30

Це означає, що ви не повинні кодувати https://xpto.example.com/path/subpathURL-адресу, а лише те, що йде після ?.

Припустимо, оскільки для цього є випадки використання:

https://example.com?redirectme=xxxxx

Де xxxxxповністю закодована URL-адреса.


0

Додавання до прийнятої відповіді. Враховуючи цю замітку

Цей метод призначений для відсоткового кодування компонента URL або рядка підкомпонента, а не цілого рядка URL.

вся URL-адреса не повинна кодуватися:

let param = "=color:green|\(latitude),\(longitude)&\("zoom=13&size=\(width)x\(height)")&sensor=true&key=\(staticMapKey)".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) 
let url = "https://maps.google.com/maps/api/staticmap?markers" + param!
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.