提问人:MegaCookie 提问时间:7/3/2014 最后编辑:Bryan ChenMegaCookie 更新时间:11/15/2023 访问量:354177
Swift - 编码 URL
Swift - encode URL
问:
如果我像这样编码字符串:
var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
它没有逃脱斜线./
我搜索并找到了这个 Objective C 代码:
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8 );
有没有一种更简单的方法来编码 URL,如果没有,我如何在 Swift 中编写它?
答:
斯威夫特 3
在 Swift 3 中,有addingPercentEncoding
let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)
输出:
测试%2F测试
斯威夫特 1
在 iOS 7 及更高版本中,有stringByAddingPercentEncodingWithAllowedCharacters
var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")
输出:
测试%2F测试
以下是有用的(反转)字符集:
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)\'")
}
评论
stringByAddingPercentEncodingWithAllowedCharacters()
&
URLQueryAllowedCharacterSet
URLComponents
URLQueryItem
一切都是一样的
var str = CFURLCreateStringByAddingPercentEscapes(
nil,
"test/test",
nil,
"!*'();:@&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)
// test%2Ftest
评论
.bridgeToOvjectiveC()
我自己需要这个,所以我写了一个字符串扩展,它既允许 URLEncoding 字符串,又允许更常见的最终目标,将参数字典转换为“GET”样式的 URL 参数:
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 & 5 (感谢@sumizome的建议。感谢@FD_和@derickito的测试)
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"
这是Bryan Chen回答的简短版本。我猜这是允许控制字符通过,除非它们构成查询字符串中键或值的一部分,此时需要转义它们。urlQueryAllowed
评论
var
.remove
斯威夫特 5:
extension String {
var urlEncoded: String? {
let allowedCharacterSet = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "~-_."))
return self.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
}
}
print("\u{48}ello\u{9}world\u{7}\u{0}".urlEncoded!) // prints Hello%09world%07%00
print("The string ü@foo-bar".urlEncoded!) // prints The%20string%20%C3%BC%40foo-bar
评论
let originalString = "\u{48}ello\u{9}world\u{7}\u{0}"
"Hello\tworld\u{07}\0"
可以使用 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
}
评论
URLQueryItem
Formula+One
Formula+One
Formula One
URLComponents
斯威夫特 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. 编码URL:
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"
评论
urlHostAllowed
?
=
+
urlHostAllowed
URLComponents
+
CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "+"))
斯威夫特 4:
这取决于您的服务器遵循的编码规则。
Apple 提供了此类方法,但它没有报告它遵循的 RCF 协议类型。
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
按照这个有用的工具,你应该保证你的参数对这些字符进行编码:
- $(美元符号)变为 %24
- &(与号)变为 %26
- + (加号) 变为 %2B
- ,(逗号)变为 %2C
- : (冒号) 变为 %3A
- ;(分号)变为 %3B
- = (等于) 变为 %3D
- ?(问号)变为 %3F
- @(商业 A / At)变为 %40
换句话说,谈到 URL 编码,您应该遵循 RFC 1738 协议。
例如,Swift 没有涵盖 + char 的编码,但它适用于这三个 @ : ? chars。
因此,要正确编码每个参数,该选项是不够的,您还应该添加特殊字符,例如:.urlHostAllowed
encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")
希望这能帮助那些变得疯狂的人搜索这些信息。
评论
斯威夫特 4 和 5
要对 URL 中的参数进行编码,我发现使用字符集是最简单的选择:.alphanumerics
let urlEncoded = value.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
let url = "http://www.example.com/?name=\(urlEncoded!)"
对 URL 编码使用任何标准字符集(like 或 )都不起作用,因为它们不排除 or 字符。.urlQueryAllowed
.urlHostAllowed
=
&
使用也无法正常工作,因为它不会转义字符。URLComponents
+
请注意,通过使用它将对一些不需要编码的字符进行编码(如 、 或 --——参见 2.3。 RFC 3986 中的非保留字符)。我发现使用比构建自定义字符集更简单,并且不介意要编码一些额外的字符。如果这困扰您,请构造一个自定义字符集,如如何对 URL 字符串进行百分比编码中所述,例如:.alphanumerics
-
.
_
~
.alphanumerics
// Store allowed character set for reuse (computed lazily).
private let urlAllowed: CharacterSet =
.alphanumerics.union(.init(charactersIn: "-._~")) // as per RFC 3986
extension String {
var urlEncoded: String? {
return addingPercentEncoding(withAllowedCharacters: urlAllowed)
}
}
let url = "http://www.example.com/?name=\(value.urlEncoded!)"
警告:参数被强制展开。对于无效的 unicode 字符串,它可能会崩溃。请参阅为什么 String.addingPercentEncoding() 的返回值是可选的?。您可以使用 or 代替强制解包。urlEncoded
urlEncoded!
urlEncoded ?? ""
if let urlEncoded = urlEncoded { ... }
评论
.aphanumerics
.urlHostAllowed
&
.urlHostAllowed
=
&
这在 Swift 5 中对我有用。用例是从剪贴板或类似内容中获取 URL,该 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
}
}
接下来,使用编码 URL 的方法进行扩展:String
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
请注意,保留了 和 间距,对 Unicode 字符进行了编码,原始字符中的 没有双重编码,并且保留了锚点(片段或 )。%20
+
%20
urlText
#
编辑:现在检查每个组件的有效性。
SWIFT 4.2 版本
有时发生这种情况只是因为 slug 中有空间或通过 API URL 传递的参数没有 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
斯威夫特 4.2
快速的单线解决方案。替换为要编码的字符串。originalString
var encodedString = originalString.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]{} ").inverted)
评论
let originalString = "\u{48}ello\u{9}world\u{7}\u{0}"
"Hello\tworld\u{07}\0"
let Url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")
对于 Swift 5 到字符串的端码
func escape(string: String) -> String {
let allowedCharacters = string.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: ":=\"#%/<>?@\\^`{|}").inverted) ?? ""
return allowedCharacters
}
如何使用?
let strEncoded = self.escape(string: "http://www.edamam.com/ontologies/edamam.owl#recipe_e2a1b9bf2d996cbd9875b80612ed9aa4")
print("escapedString: \(strEncoded)")
这些答案都不适合我。当 url 包含非英文字符时,我们的应用程序崩溃了。
let unreserved = "-._~/?%$!:"
let allowed = NSMutableCharacterSet.alphanumeric()
allowed.addCharacters(in: unreserved)
let escapedString = urlString.addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)
根据您尝试执行的操作的参数,您可能只想创建自己的字符集。以上允许使用英文字符,并且-._~/?%$!:
对我有帮助的是,我创建了一个单独的字符串,并将其用于 UTF-8 编码的字符串,即 textToEncode 来生成所需的结果:NSCharacterSet
var queryCharSet = NSCharacterSet.urlQueryAllowed
queryCharSet.remove(charactersIn: "+&?,:;@+=$*()")
let utfedCharacterSet = String(utf8String: textToEncode.cString(using: .utf8)!)!
let encodedStr = utfedCharacterSet.addingPercentEncoding(withAllowedCharacters: queryCharSet)!
let paramUrl = "https://api.abc.eu/api/search?device=true&query=\(escapedStr)"
评论
斯威夫特 5你可以试试。afURLQueryAllowed 选项,如果要对字符串进行编码,如下所示
let testString = "6hAD9/RjY+SnGm&B"
let escodedString = testString.addingPercentEncoding(withAllowedCharacters: .afURLQueryAllowed)
print(escodedString!)
编码的字符串将类似于 en6hAD9%2FRjY%2BSnGm%26B
评论
版本:Swift 5
// space convert to +
let mstring = string.replacingOccurrences(of: " ", with: "+")
// remove special character
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: "!*'\"();:@&=+$,/?%#[]%")
return mstring.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey) ?? mstring
评论
+
可用于表示空格,但需要正确转义现有的实例。这个答案是不该做什么的一个例子。+
我曾经遇到过这样的字符串问题(其中某些部分已经编码)。%5B×××%5D
我花了一个小时才意识到它可以很容易地解决:
extension String {
var decodeThenEncodeURL: String {
removingPercentEncoding?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? self
}
}
- 输入:
https://www.google.com/search?q=%5B×××%5D
- 输出:
https://www.google.com/search?q=%5B%C3%97%C3%97%C3%97%5D
这更好,更权威。它引用了Almofire URLEncodedFormEncoder.swift
extension CharacterSet {
/// Creates a CharacterSet from RFC 3986 allowed characters.
///
/// RFC 3986 states that the following characters are "reserved" characters.
///
/// - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
/// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
///
/// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
/// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
/// should be percent-escaped in the query string.
public static let afURLQueryAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
let encodableDelimiters = CharacterSet(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
return CharacterSet.urlQueryAllowed.subtracting(encodableDelimiters)
}()
}
评论