[SWIFT] Arguments of String.addingPercentEncoding (withAllowedCharacters :)

I was curious about what String.addingPercentEncoding (withAllowedCharacters :) encodes, so I looked it up. I also compared the value part of queryItems in URLComponents with encodeURI and encodeURIComponent in JavaScriptCore. It's annoying. By the way, if you try to encode all the symbols and use .alphanumerics, there is a trap that accented alphabets (such as é) and so-called double-byte alphanumeric characters are not encoded.

CharacterSet ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ |] ^ _ ` { | } ~
urlFragmentAllowed
urlHostAllowed
urlPasswordAllowed
urlPathAllowed
urlQueryAllowed
urlUserAllowed
URLComponents
encodeURI
encodeURIComponent
import Foundation
import JavaScriptCore

let asciiSymbols = (0x20...0x7e)
    .map { Unicode.Scalar($0) }
    .filter { !CharacterSet.alphanumerics.contains($0) }

let allowdChars = { (str: String) -> String in
    let regexp = try! NSRegularExpression(pattern: "%[0-9A-F][0-9A-F]")
    let range = NSRange(str.startIndex..., in: str)
    return regexp.stringByReplacingMatches(in: str, range: range, withTemplate: "")
}

let urlComponents = { () -> String in
    var comp = URLComponents(string: "https://example.com/")!
    comp.queryItems = [URLQueryItem(name: "q", value: asciiSymbols.map { String($0) }.joined())]
    return allowdChars(comp.url!.absoluteString.components(separatedBy: "=")[1])
}()

let context = JSContext()!
context.evaluateScript("var ascii = ''; for (var i = 0x20; i < 0x7f; i++) ascii += String.fromCharCode(i)")
context.evaluateScript("var result = encodeURI(ascii)")
let encodeURI = allowdChars(context.objectForKeyedSubscript("result")!.toString()!)
context.evaluateScript("var result = encodeURIComponent(ascii)")
let encodeURIComponent = allowdChars(context.objectForKeyedSubscript("result")!.toString()!)

let charsets: [(String, CharacterSet)] = [
    ("urlFragmentAllowed", .urlFragmentAllowed),
    ("urlHostAllowed",     .urlHostAllowed),
    ("urlPasswordAllowed", .urlPasswordAllowed),
    ("urlPathAllowed",     .urlPathAllowed),
    ("urlQueryAllowed",    .urlQueryAllowed),
    ("urlUserAllowed",     .urlUserAllowed),
    ("URLComponents",      CharacterSet(charactersIn: urlComponents)),
    ("encodeURI",          CharacterSet(charactersIn: encodeURI)),
    ("encodeURIComponent", CharacterSet(charactersIn: encodeURIComponent)),
]
print("|CharacterSet|" + asciiSymbols.map { String($0) }.map { ($0 == "|" ? "&#124;" : $0) + "|" }.joined())
print("|:--|" + asciiSymbols.map { _ in ":-:|" }.joined())
for cs in charsets {
    print("|\(cs.0)|" + asciiSymbols.map { (cs.1.contains($0) ? "" : "✅") + "|" }.joined())
}

Recommended Posts

Arguments of String.addingPercentEncoding (withAllowedCharacters :)
wrong number of arguments (given 1, expected 0)
Make a note of Ruby keyword arguments
Summary of how to write annotation arguments