web-dev-qa-db-fra.com

Swift - encoder l'URL

Si je code une chaîne comme ceci: 

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

il n'échappe pas aux barres obliques /

J'ai cherché et trouvé ce code Objective C: 

NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
                        NULL,
                        (CFStringRef)unencodedString,
                        NULL,
                        (CFStringRef)@"!*'();:@&=+$,/?%#[]",
                        kCFStringEncodingUTF8 );

Existe-t-il un moyen plus simple de coder une URL et si non, comment puis-je l'écrire dans Swift?

234
MegaCookie

Swift 3

Dans Swift 3, il y a addingPercentEncoding

let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)

Sortie:

test% 2Ftest

Swift 1

Dans iOS 7 et supérieur, il y a stringByAddingPercentEncodingWithAllowedCharacters

var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")

Sortie: 

test% 2Ftest

Voici des jeux de caractères utiles (inversés): 

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

Si vous souhaitez échapper un jeu de caractères différent, créez-en un:
Exemple avec le caractère "=" ajouté:

var originalString = "test/test=42"
var customAllowedSet =  NSCharacterSet(charactersInString:"=\"#%/<>?@\\^`{|}").invertedSet
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(customAllowedSet)
println("escapedString: \(escapedString)")

Sortie: 

test% 2Ftest% 3D42

Exemple pour vérifier les caractères ASCII qui ne sont pas dans le jeu:

func printCharactersInSet(set: NSCharacterSet) {
    var characters = ""
    let iSet = set.invertedSet
    for i: UInt32 in 32..<127 {
        let c = Character(UnicodeScalar(i))
        if iSet.longCharacterIsMember(i) {
            characters = characters + String(c)
        }
    }
    print("characters not in set: \'\(characters)\'")
}
504
zaph

Vous pouvez utiliser URLComponents pour éviter de devoir manuellement échapper le pourcentage de votre chaîne de requête:

let scheme = "https"
let Host = "www.google.com"
let path = "/search"
let queryItem = URLQueryItem(name: "q", value: "Formula One")


var urlComponents = URLComponents()
urlComponents.scheme = scheme
urlComponents.Host = Host
urlComponents.path = path
urlComponents.queryItems = [queryItem]

if let url = urlComponents.url {
    print(url)   // "https://www.google.com/search?q=Formula%20One"
}

extension URLComponents {
    init(scheme: String = "https",
         Host: String = "www.google.com",
         path: String = "/search",
         queryItems: [URLQueryItem]) {
        self.init()
        self.scheme = scheme
        self.Host = Host
        self.path = path
        self.queryItems = queryItems
    }
}

let query = "Formula One"
if let url = URLComponents(queryItems: [URLQueryItem(name: "q", value: query)]).url {
    print(url)  // https://www.google.com/search?q=Formula%20One
}
43
Leo Dabus

Swift 3:

let allowedCharacterSet = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted)

if let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) {
//do something with escaped string
}
32
Hong Wei

Swift 3:

let originalString = "http://www.ihtc.cc?name=htc&title=iOS开发工程师"

1. encodingQuery:

let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)

résultat:

"http://www.ihtc.cc?name=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88" 

2. encodingURL:

let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)

résultat:

"http:%2F%2Fwww.ihtc.cc%3Fname=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"
21
iHTCboy

Swift 4

Pour encoder un paramètre dans l'URL, l'utilisation du caractère .alphanumerics est la plus simple:

let encoded = parameter.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
let url = "http://www.example.com/?name=\(encoded!)"

L'utilisation de l'un des jeux de caractères standard pour le codage d'URL (tels que URLQueryAllowedCharacterSet ou URLHostAllowedCharacterSet) ne fonctionnera pas, car ils n'excluent pas les caractères = ou &.

Notez qu'en utilisant .alphanumerics, il encodera certains caractères qui n'ont pas besoin d'être encodés (comme -, ., _ ou ~ -– voir 2.3. Caractères non réservés dans RFC 3986). Je trouve que l'utilisation de .alphanumerics est plus simple que de construire un jeu de caractères personnalisé et que certains caractères supplémentaires ne doivent pas être codés. Si cela vous dérange, construisez un jeu de caractères personnalisé comme décrit dans Comment encoder une URL par un pourcentage , comme par exemple:

var allowed = CharacterSet.alphanumerics
allowed.insert(charactersIn: "-._~") // as per RFC 3986
let encoded = parameter.addingPercentEncoding(withAllowedCharacters: allowed)
let url = "http://www.example.com/?name=\(encoded!)"

Avertissement: Le paramètre encoded est forcé non emballé. Pour une chaîne unicode non valide, il peut se bloquer. Voir Pourquoi la valeur de retour de String.addingPercentEncoding () est-elle facultative? . Au lieu de forcer le déconditionnement de encoded!, vous pouvez utiliser encoded ?? "" ou utiliser if let encoded = ....

15
Marián Černý

Tout est pareil

var str = CFURLCreateStringByAddingPercentEscapes(
    nil,
    "test/test",
    nil,
    "!*'();:@&=+$,/?%#[]",
    CFStringBuiltInEncodings.UTF8.rawValue
)

// test%2Ftest
12
Bryan Chen

Swift 4 (non testé - veuillez indiquer si cela fonctionne ou non. Merci @sumizome pour vos suggestions)

var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: ";/?:@&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)

Swift 3

let allowedQueryParamAndKey =  NSCharacterSet.urlQueryAllowed.remove(charactersIn: ";/?:@&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)

Swift 2.2 (emprunté à Zaph et corrigé pour la clé de requête et les valeurs de paramètre)

var allowedQueryParamAndKey =  NSCharacterSet(charactersInString: ";/?:@&=+$, ").invertedSet
paramOrKey.stringByAddingPercentEncodingWithAllowedCharacters(allowedQueryParamAndKey)

Exemple:

let paramOrKey = "https://some.website.com/path/to/page.srf?a=1&b=2#top"
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
// produces:
"https%3A%2F%2Fsome.website.com%2Fpath%2Fto%2Fpage.srf%3Fa%3D1%26b%3D2%23top"

Ceci est une version plus courte de la réponse de Bryan Chen. J'imagine que urlQueryAllowed autorise les caractères de contrôle, ce qui est correct, à moins qu'ils ne fassent partie de la clé ou de la valeur de votre chaîne de requête à quel point ils doivent être ignorés.

10
AJP

Swift 4:

Cela dépend des règles d'encodage suivies par votre serveur.

Apple propose cette méthode de classe, mais ne précise pas quel type de protocole RCF elle suit.

var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!

En suivant cet utile outil , vous devez garantir le codage de ces caractères pour vos paramètres:

  • $ (Dollar Sign) devient% 24
  • & (Esperluette) devient% 26
  • + (Plus) devient% 2B
  • , (Virgule) devient% 2C
  • : (Deux points) devient% 3A
  • ; (Point-virgule) devient% 3B
  • = (Égal) devient% 3D
  • ? (Point d'interrogation) devient% 3F
  • @ (Commercial A/At) devient% 40

En d'autres termes, en ce qui concerne le codage d'URL, vous devriez suivre le protocole RFC 1738 .

Et Swift ne couvre pas l'encodage du + caractère par exemple, mais cela fonctionne bien avec ces trois @:? caractères.

Donc, pour encoder correctement chacun de vos paramètres, l'option .urlHostAllowed ne suffit pas, vous devez également ajouter les caractères spéciaux comme par exemple:

encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")

J'espère que cela aide quelqu'un qui devient fou à rechercher ces informations.

8

J'avais besoin de cela moi-même, alors j'ai écrit une extension String qui permet à la fois de créer des chaînes URLEncoding, ainsi que l'objectif plus commun, convertir un dictionnaire de paramètres en style "GET"

extension String {
    func URLEncodedString() -> String? {
        var escapedString = self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
        return escapedString
    }
    static func queryStringFromParameters(parameters: Dictionary<String,String>) -> String? {
        if (parameters.count == 0)
        {
            return nil
        }
        var queryString : String? = nil
        for (key, value) in parameters {
            if let encodedKey = key.URLEncodedString() {
                if let encodedValue = value.URLEncodedString() {
                    if queryString == nil
                    {
                        queryString = "?"
                    }
                    else
                    {
                        queryString! += "&"
                    }
                    queryString! += encodedKey + "=" + encodedValue
                }
            }
        }
        return queryString
    }
}

Prendre plaisir!

4
BadPirate

Celui-ci travaille pour moi.

func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String? {

    let unreserved = "*-._"
    let allowed = NSMutableCharacterSet.alphanumericCharacterSet()
    allowed.addCharactersInString(unreserved)

    if plusForSpace {
        allowed.addCharactersInString(" ")
    }

    var encoded = stringByAddingPercentEncodingWithAllowedCharacters(allowed)

    if plusForSpace {
        encoded = encoded?.stringByReplacingOccurrencesOfString(" ", withString: "+")
    }
    return encoded
}

J'ai trouvé la fonction ci-dessus à partir de ce lien: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/ .

2
Gaurav Singla

Swift 4.2

Une solution rapide en une ligne. Remplacez originalString par la chaîne que vous souhaitez encoder.

var encodedString = originalString.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]{} ").inverted)

Démo de terrain de jeu en ligne

0
ajzbc

Swift 4.2

Cela se produit parfois simplement parce qu'il y a de la place dans slug OR en l'absence de codage d'URL pour les paramètres transmis via l'URL de l'API.

let myString = self.slugValue
                let csCopy = CharacterSet(bitmapRepresentation: CharacterSet.urlPathAllowed.bitmapRepresentation)
                let escapedString = myString!.addingPercentEncoding(withAllowedCharacters: csCopy)!
                //always "info:hello%20world"
                print(escapedString)

NOTE: N'oubliez pas d'explorer environ bitmapRepresentation.

0
Vrushal Raut