Swift - кодировать URL-адрес
Если я кодирую строку следующим образом:
var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
он не выходит из косой черты /
.
Я искал и нашел этот код Objective C:
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8 );
Есть ли более простой способ кодирования URL-адреса, а если нет, как это записать в Swift?
Ответы
Ответ 1
Свифт 3
В Swift 3 есть addingPercentEncoding
let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)
Выход:
Тест% 2Ftest
Свифт 1
В iOS 7 и выше есть stringByAddingPercentEncodingWithAllowedCharacters
var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")
Выход:
Тест% 2Ftest
Ниже приведены полезные (инвертированные) наборы символов:
URLFragmentAllowedCharacterSet "#%<>[\]^'{|}
URLHostAllowedCharacterSet "#%/<>[email protected]\^'{|}
URLPasswordAllowedCharacterSet "#%/:<>[email protected][\]^'{|}
URLPathAllowedCharacterSet "#%;<>?[\]^'{|}
URLQueryAllowedCharacterSet "#%<>[\]^'{|}
URLUserAllowedCharacterSet "#%/:<>[email protected][\]^'
Если вы хотите экранировать другой набор символов, создайте набор:
Пример с добавленным символом "=":
var originalString = "test/test=42"
var customAllowedSet = NSCharacterSet(charactersInString:"=\"#%/<>[email protected]\\^'{|}").invertedSet
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(customAllowedSet)
println("escapedString: \(escapedString)")
Выход:
Тест% 2Ftest% 3D42
Пример проверки символов ascii, не входящих в набор:
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)\'")
}
Ответ 2
Вы можете использовать URLComponents, чтобы избежать необходимости вручную экранировать процент вашей строки запроса:
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
}
Ответ 3
Swift 3:
let allowedCharacterSet = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted)
if let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) {
//do something with escaped string
}
Ответ 4
Swift 3:
let originalString = "http://www.ihtc.cc?name=htc&title=iOS开发工程师"
1. encodingQuery:
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
результат:
"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)
результат:
"http:%2F%2Fwww.ihtc.cc%3Fname=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"
Ответ 5
Swift 4
Для кодирования параметра в URL я нахожу, используя .alphanumerics
символов .alphanumerics
самый простой вариант:
let encoded = parameter.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
let url = "http://www.example.com/?name=\(encoded!)"
Использование любого из стандартных наборов символов для кодирования URL (например, URLQueryAllowedCharacterSet
или URLHostAllowedCharacterSet
) не будет работать, поскольку они не исключают символы =
или &
.
Обратите внимание, что при использовании .alphanumerics
он будет кодировать некоторые символы, которые не нужно кодировать (например, -
, .
, _
Или ~
- - см. 2.3. Незарезервированные символы в RFC 3986). Я считаю, что использование .alphanumerics
проще, чем создание собственного набора символов, и я не против некоторых дополнительных символов, которые нужно кодировать. Если это вас беспокоит, создайте пользовательский набор символов, как описано в разделе Как в процентах кодировать строку URL, например, так:
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!)"
Предупреждение: encoded
параметр принудительно развернут. Для недопустимой строки Unicode может произойти сбой. См. Почему возвращаемое значение String.addingPercentEncoding() необязательно? , Вместо encoded!
принудительной распаковки encoded!
вы можете использовать encoded?? ""
encoded?? ""
или используйте, if let encoded =...
Ответ 6
Все одинаково
var str = CFURLCreateStringByAddingPercentEscapes(
nil,
"test/test",
nil,
"!*'();:@&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)
// test%2Ftest
Ответ 7
Swift 4 (не проверено - прокомментируйте, работает ли оно или нет. Спасибо @sumizome за предложение)
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: ";/?:@&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Свифт 3
let allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed.remove(charactersIn: ";/?:@&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Swift 2.2 (заимствование у Zaph и исправление ключа URL-адреса и значений параметров)
var allowedQueryParamAndKey = NSCharacterSet(charactersInString: ";/?:@&=+$, ").invertedSet
paramOrKey.stringByAddingPercentEncodingWithAllowedCharacters(allowedQueryParamAndKey)
Пример:
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"
Это более короткая версия ответа Брайана Чена. Я предполагаю, что urlQueryAllowed
разрешает управляющие символы, с помощью которых все в порядке, если только они не образуют часть ключа или значения в строке запроса, и в этот момент их необходимо экранировать.
Ответ 8
Swift 4:
Это зависит от правил кодирования, за которыми следует ваш сервер.
Apple предлагает этот метод класса, но он не сообщает о каком-то RCF-протоколе.
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
Следуя этому полезному инструменту, вы должны гарантировать кодирование этих символов для ваших параметров:
- $ (Знак доллара) становится% 24
- & (Амперсанд) становится% 26
- + (Плюс) становится% 2B
- , (Comma) становится% 2C
- : (Colon) становится% 3A
- ; (Полуколон) становится% 3B
- = (Равно) становится% 3D
- ? (Question Mark) становится% 3F
- @(Commercial A/At) становится% 40
Другими словами, говоря о кодировке URL, вы должны следовать протоколу RFC 1738.
И Swift не покрывает кодировку + char, например, но он хорошо работает с этими тремя @:? символы.
Итак, чтобы правильно кодировать каждый ваш параметр, параметра .urlHostAllowed
недостаточно, вы должны также добавить специальные символы, например:
encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")
Надеюсь, это поможет кому-то, кто сходит с ума, искать эту информацию.
Ответ 9
Мне нужно это, поэтому я написал расширение String, которое позволяет использовать строки URLEncoding, а также более общую конечную цель: преобразование словаря параметров в параметр URL-адреса стиля "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
}
}
Наслаждайтесь!
Ответ 10
Этот работает для меня.
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
}
Я нашел функцию выше по этой ссылке: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/.
Ответ 11
Swift 4.2
Быстрое решение в одну строку. Замените originalString
строкой, которую вы хотите кодировать.
var encodedString = originalString.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]{} ").inverted)
Демоверсия игровой площадки
Ответ 12
Swift 4: Вы можете закодировать URL с помощью этого:
if let encoded = url.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed),
let url = URL(string: encoded)
{
print(url)
// if you want convert URL to String
url = url.absoluteString
}
Ответ 13
SWIFT 4.2
Иногда это происходит только потому, что в слаге ИЛИ отсутствует кодировка URL для параметров, проходящих через API URL.
let myString = self.slugValue
let csCopy = CharacterSet(bitmapRepresentation: CharacterSet.urlPathAllowed.bitmapRepresentation)
let escapedString = myString!.addingPercentEncoding(withAllowedCharacters: csCopy)!
//always "info:hello%20world"
print(escapedString)
ПРИМЕЧАНИЕ: не забудьте изучить bitmapRepresentation
.
Ответ 14
Это работает для меня в Swift 5. В случае использования берется URL-адрес из буфера обмена или аналогичный, который, возможно, уже содержит экранированные символы, но также содержит символы Unicode, что может привести к URLComponents
или URL(string:)
.
Сначала создайте набор символов, который включает все допустимые для URL символы:
extension CharacterSet {
/// Characters valid in at least one part of a URL.
///
/// These characters are not allowed in ALL parts of a URL; each part has different requirements. This set is useful for checking for Unicode characters that need to be percent encoded before performing a validity check on individual URL components.
static var urlAllowedCharacters: CharacterSet {
// Start by including hash, which isn't in any set
var characters = CharacterSet(charactersIn: "#")
// All URL-legal characters
characters.formUnion(.urlUserAllowed)
characters.formUnion(.urlPasswordAllowed)
characters.formUnion(.urlHostAllowed)
characters.formUnion(.urlPathAllowed)
characters.formUnion(.urlQueryAllowed)
characters.formUnion(.urlFragmentAllowed)
return characters
}
}
Далее, расширьте String
методом для кодирования URL:
extension String {
/// Converts a string to a percent-encoded URL, including Unicode characters.
///
/// - Returns: An encoded URL if all steps succeed, otherwise nil.
func encodedUrl() -> URL? {
// Remove preexisting encoding,
guard let decodedString = self.removingPercentEncoding,
// encode any Unicode characters so URLComponents doesn't choke,
let unicodeEncodedString = decodedString.addingPercentEncoding(withAllowedCharacters: .urlAllowedCharacters),
// break into components to use proper encoding for each part,
let components = URLComponents(string: unicodeEncodedString),
// and reencode, to revert decoding while encoding missed characters.
let percentEncodedUrl = components.url else {
// Encoding failed
return nil
}
return percentEncodedUrl
}
}
Который может быть проверен как:
let urlText = "https://www.example.com/폴더/search?q=123&foo=bar&multi=eggs+and+ham&hangul=한글&spaced=lovely%20spam&illegal=<>#top"
let url = encodedUrl(from: urlText)
Значение url
в конце: https://www.example.com/%ED%8F%B4%EB%8D%94/search?q=123&foo=bar&multi=eggs+and+ham&hangul=%ED%95%9C%EA%B8%80&spaced=lovely%20spam&illegal=%3C%3E#top
Обратите внимание, что сохраняются оба %20
и +
интервал, символы Unicode кодируются, %20
в исходном urlText
не кодируется дважды, а привязка (фрагмент или #
) остается.
Редактировать: теперь проверка на правильность каждого компонента.
Ответ 15
let Url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters:.urlQueryAllowed)?? "")