Если я кодирую строку следующим образом:
var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
он не выходит из косой черты /
.
Я искал и нашел этот код Objective C:
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8 );
Есть ли более простой способ кодирования URL-адреса, а если нет, как это записать в Swift?
В Swift 3 есть addingPercentEncoding
let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)
Выход:
Тест% 2Ftest
В iOS 7 и выше есть stringByAddingPercentEncodingWithAllowedCharacters
var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")
Выход:
Тест% 2Ftest
Ниже приведены полезные (инвертированные) наборы символов:
URLFragmentAllowedCharacterSet "#%<>[\]^'{|}
URLHostAllowedCharacterSet "#%/<>?@\^'{|}
URLPasswordAllowedCharacterSet "#%/:<>?@[\]^'{|}
URLPathAllowedCharacterSet "#%;<>?[\]^'{|}
URLQueryAllowedCharacterSet "#%<>[\]^'{|}
URLUserAllowedCharacterSet "#%/:<>?@[\]^'
Если вы хотите экранировать другой набор символов, создайте набор:
Пример с добавленным символом "=":
var originalString = "test/test=42"
var customAllowedSet = NSCharacterSet(charactersInString:"=\"#%/<>?@\\^'{|}").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)\'")
}
Вы можете использовать URLComponents, чтобы избежать того, чтобы вручную избежать escape-строки запроса:
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
}
URLQueryItem
не всегда правильно кодирует. Например, Formula+One
будет закодирована в Formula+One
, которая будет декодирована в Formula One
. Поэтому будьте осторожны со знаком плюс.
Swift 3:
let allowedCharacterSet = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted)
if let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) {
//do something with escaped string
}
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"
Для кодирования параметра в 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 =...
Все одинаково
var str = CFURLCreateStringByAddingPercentEscapes(
nil,
"test/test",
nil,
"!*'();:@&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)
// test%2Ftest
.bridgeToOvjectiveC()
второй аргумент .bridgeToOvjectiveC()
и не получили "Невозможно преобразовать тип выражения 'CFString!' набрать 'CFString!' "?
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
разрешает управляющие символы, с помощью которых все в порядке, если только они не образуют часть ключа или значения в строке запроса, и в этот момент их необходимо экранировать.
var
), а затем вызовите .remove
для него на втором этапе.
Это зависит от правил кодирования, за которыми следует ваш сервер.
Apple предлагает этот метод класса, но он не сообщает о каком-то RCF-протоколе.
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
Следуя этому полезному инструменту, вы должны гарантировать кодирование этих символов для ваших параметров:
Другими словами, говоря о кодировке URL, вы должны следовать протоколу RFC 1738.
И Swift не покрывает кодировку + char, например, но он хорошо работает с этими тремя @:? символы.
Итак, чтобы правильно кодировать каждый ваш параметр, параметра .urlHostAllowed
недостаточно, вы должны также добавить специальные символы, например:
encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")
Надеюсь, это поможет кому-то, кто сходит с ума, искать эту информацию.
Мне нужно это, поэтому я написал расширение 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
}
}
Наслаждайтесь!
&
или =
в параметрах. Проверьте мое решение вместо этого.
Этот работает для меня.
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/.
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
.
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
}
Это работает для меня в Swift 4.2. В случае использования берется URL-адрес из буфера обмена или аналогичный, который, возможно, уже содержит экранированные символы, но также содержит символы Unicode, которые могут привести к сбою URL(string:)
.
func encodedUrl(from string: String) -> URL? {
// Remove preexisting encoding
guard let decodedString = string.removingPercentEncoding,
// Reencode, to revert decoding while encoding missed characters
let percentEncodedString = decodedString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
// Coding failed
return nil
}
// Create URL from encoded string, or nil if failed
return URL(string: percentEncodedString)
}
let urlText = "https://www.example.com/폴더/search?q=123&foo=bar&multi=eggs+and+ham&hangul=한글&spaced=lovely%20spam&illegal=<>"
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
Обратите внимание, что %20
и +
интервал сохраняются, символы Unicode кодируются, а %20
в исходном urlText
не кодируется дважды.
Предостережение: это ярлык, так как он использует .urlQueryAllowed
для всего URL; он также предполагает, что URL уже работал в браузере. Используйте с умом! Я также открыт для предложений (я остановился на том, чтобы URLComponents
весь URL с помощью URLComponents
, применить отдельные наборы символов и пересобрать).