Swift: codifica la URL

Si codifico una cadena como esta:

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) 

no escapa a las barras / .

He buscado y encontrado este código de Objective C:

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

¿Existe alguna manera más fácil de codificar una URL y, de no ser así, cómo escribo esto en Swift?

Swift 3

En Swift 3 hay addingPercentEncoding

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

Salida:

prueba% 2Ftest

Swift 1

En iOS 7 y superior hay stringByAddingPercentEncodingWithAllowedCharacters

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

Salida:

prueba% 2Ftest

Los siguientes son conjuntos de caracteres útiles (invertidos):

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

Si desea que se escape un conjunto diferente de caracteres, cree un conjunto:
Ejemplo con el carácter “=” agregado:

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

Salida:

prueba% 2Ftest% 3D42

Ejemplo para verificar los caracteres ascii que no están en el conjunto:

 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)\'") } 

Puedes usar URLComponents para evitar tener que escatimar por ciento manualmente la cadena de consulta:

 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, host: String, path: String, queryItems: [URLQueryItem]) { self.init() self.scheme = scheme self.host = host self.path = path self.queryItems = queryItems } } if let url = URLComponents(scheme: "https", host: "www.google.com", path: "/search", queryItems: [URLQueryItem(name: "q", value: "Formula One")]).url { print(url) // https://www.google.com/search?q=Formula%20One } 

Swift 3:

 let allowedCharacterSet = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted) if let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) { //do something with escaped string } 

Swift 3:

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

1. encodingQuery:

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

resultado:

 "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) 

resultado:

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

Todo es lo mismo

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

Swift 4

Para codificar un parámetro en URL, encuentro que el uso del carácter .alphanumerics establece la opción más fácil:

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

El uso de cualquiera de los conjuntos de caracteres estándar para encoding de URL (como URLQueryAllowedCharacterSet o URLHostAllowedCharacterSet ) no funcionará, ya que no excluyen = o & caracteres.

Tenga en cuenta que al utilizar .alphanumerics codificará algunos caracteres que no necesitan ser codificados (como . , - o _ ). Me resulta más .alphanumerics utilizar .alphanumerics que construir un juego de caracteres personalizado y no me importan algunos caracteres adicionales para codificar. Si eso te molesta, construye un juego de caracteres personalizado como se describe en Cómo codificar por ciento una cadena URL , como por ejemplo:

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

Advertencia: el parámetro encoded desenrolla por la fuerza. Para una cadena Unicode no válida, puede bloquearse. Consulte ¿Por qué es opcional el valor de retorno de String.addingPercentEncoding ()? . En lugar de desenrollar la fuerza encoded! puedes usar encoded ?? "" encoded ?? "" o use if let encoded = ...

Swift 3

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

Swift 2.2 (tomando prestado de Zaph y corrigiendo la clave de consulta url y los valores de los parámetros)

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

Ejemplo:

 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" 

Esta es una versión más corta de la respuesta de Bryan Chen. Supongo que urlQueryAllowed está permitiendo a los personajes de control a través del cual está bien, a menos que formen parte de la clave o el valor en la cadena de consulta, en cuyo punto deben escaparse.

Swift 4:

Depende de las reglas de encoding seguidas por su servidor.

Apple ofrece este método de clase, pero no informa qué tipo de protocolo RCF sigue.

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

Siguiendo esta útil herramienta , debe garantizar la encoding de estos caracteres para sus parámetros:

  • $ (Signo de dólar) se convierte en% 24
  • & (Ampersand) se convierte en% 26
  • + (Más) se convierte en% 2B
  • , (Coma) se convierte en% 2C
  • : (Colon) se convierte en% 3A
  • ; (Semi-Colon) se convierte en% 3B
  • = (Igual) se convierte en% 3D
  • ? (Signo de interrogación) se convierte en% 3F
  • @ (Comercial A / At) se convierte en% 40

En otras palabras, hablando de encoding URL, debe seguir el protocolo RFC 1738 .

Y Swift no cubre la encoding del + char por ejemplo , pero funciona bien con estos tres @:? Chars.

Por lo tanto, para codificar correctamente cada uno de sus parámetros, la opción .urlHostAllowed no es suficiente, debe agregar también los caracteres especiales como, por ejemplo:

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

Espero que esto ayude a alguien que se vuelva loco para buscar estas informaciones.

Tenía necesidad de esto yo mismo, así que escribí una extensión de cadena que permite URLEncoding cadenas, así como el objective final más común, convertir un diccionario de parámetros en parámetros de URL de estilo “GET”:

 extension String { func URLEncodedString() -> String? { var escapedString = self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) return escapedString } static func queryStringFromParameters(parameters: Dictionary) -> 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 } } 

¡Disfrutar!

Este está trabajando para mí.

 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 } 

Encontré la función anterior en este enlace: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/ .