Schnell - URL verschlüsseln


295

Wenn ich eine Zeichenfolge wie folgt codiere:

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

es entgeht nicht den Schrägstrichen /.

Ich habe diesen Objective C-Code gesucht und gefunden:

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

Gibt es eine einfachere Möglichkeit, eine URL zu verschlüsseln, und wenn nicht, wie schreibe ich diese in Swift?

Antworten:


613

Swift 3

In Swift 3 gibt es addingPercentEncoding

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

Ausgabe:

test% 2Ftest

Schnell 1

In iOS 7 und höher gibt es stringByAddingPercentEncodingWithAllowedCharacters

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

Ausgabe:

test% 2Ftest

Die folgenden nützlichen (invertierten) Zeichensätze sind:

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

Wenn Sie möchten, dass ein anderer Zeichensatz maskiert wird, erstellen Sie einen Satz:
Beispiel mit hinzugefügtem "=" - Zeichen:

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

Ausgabe:

test% 2Ftest% 3D42

Beispiel zum Überprüfen von ASCII-Zeichen, die nicht im Satz enthalten sind:

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

6
Ist sonst niemand völlig verblüfft darüber, wie lange dieser Code dazu benötigt? Ich meine, der Methodenname ist schon verdammt lang, auch ohne den erlaubten Zeichensatz zu wählen.
Thatidiotguy

38
Nein, ich bevorzuge Verständlichkeit gegenüber kurzen, knappen Namen. Autocomplete lindert die Schmerzen. stringByAddingPercentEncodingWithAllowedCharacters()lässt wenig Zweifel darüber, was es tut. Interessanter Kommentar, wenn man bedenkt, wie lange das Wort "verblüfft" ist.
Zaph

1
stringByAddingPercentEncodingWithAllowedCharacters (.URLHostAllowedCharacterSet ()) Codiert nicht alle Zeichen richtig Bryan Chens Antwort ist eine bessere Lösung.
Julio Garcia

2
@zaph Ich habe &den Zeichensatz von hinzugefügt URLQueryAllowedCharacterSetund jedes Zeichen codiert. Mit iOS 9 überprüft, sieht aus wie ein Buggy, ich habe mich für die Antwort von @ bryanchen entschieden, es funktioniert gut !!
Akash Kava

3
Die Antwort unten verwendet URLComponentsund URLQueryItemist viel sauberer IMO.
Aaron Brager

65

Sie können URLComponents verwenden, um zu vermeiden, dass Sie Ihre Abfragezeichenfolge manuell prozentual codieren müssen:

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
}

7
Diese Antwort erfordert mehr Aufmerksamkeit, da es Probleme mit allen anderen gibt (obwohl sie fairerweise zu diesem Zeitpunkt möglicherweise die beste Vorgehensweise waren).
Asa

4
Leider URLQueryItemkodiert nicht immer richtig. Zum Beispiel Formula+Onewürde codiert werden Formula+One, was decodiert würde Formula One. Seien Sie daher vorsichtig mit dem Pluszeichen.
Sulthan

37

Swift 3:

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

1. encodingQuery:

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

Ergebnis:

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

Ergebnis:

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

Ich habe die erste Lösung verwendet, möchte aber meinen Text zurückgeben, z. B. iOS 开发 工程师.
Akshay Phulare

2
Verwenden urlHostAllowedfür die Codierung von Abfrageparametern in falsch, weil es nicht codiert ?, =und +. Beim Codieren von Abfrageparametern müssen Sie Parametername und -wert separat und korrekt codieren. Dies funktioniert im Allgemeinen nicht.
Sulthan

@ Sulthan .. Haben Sie eine Lösung / Alternative fürurlHostAllowed
Bharath

@Bharath Ja, Sie müssen einen Zeichensatz selbst erstellen , z. B. stackoverflow.com/a/39767927/669586 oder einfach verwenden URLComponents.
Sulthan

URLComponents codieren das Zeichen auch nicht +. Die einzige Möglichkeit besteht darin, dies manuell zu tun:CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "+"))
SoftDesigner

36

Swift 3:

let allowedCharacterSet = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted)

if let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) {
//do something with escaped string
}

2
Sie müssen `` (Leerzeichen) in die Zeichenfolge aufnehmen
AJP

1
Sie müssen auch ^
Mani

26

Swift 4

Um einen Parameter in einer URL zu codieren, finde ich die Verwendung des .alphanumericsZeichensatzes die einfachste Option:

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

Unter Verwendung einer der Standardzeichensätze für URL - Kodierung (wie URLQueryAllowedCharacterSetoder URLHostAllowedCharacterSet) wird nicht funktionieren, weil sie es nicht tun ausschließen =oder& Zeichen.

Beachten Sie, dass durch die Verwendung .alphanumericses einige Zeichen kodieren, die nicht brauchen codiert werden (wie -, ., _oder ~- siehe 2.3 Unreserved Zeichen. In RFC 3986). Ich finde die Verwendung .alphanumericseinfacher als das Erstellen eines benutzerdefinierten Zeichensatzes und habe nichts dagegen, einige zusätzliche Zeichen zu codieren. Wenn Sie das stört, erstellen Sie einen benutzerdefinierten Zeichensatz, wie unter So codieren Sie eine URL- Zeichenfolge in Prozent beschrieben , wie zum Beispiel:

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

Warnung: Der encodedParameter wird zwangsweise entpackt. Bei ungültigen Unicode-Zeichenfolgen kann es zum Absturz kommen. Siehe Warum ist der Rückgabewert von String.addingPercentEncoding () optional? . Anstatt das Auspacken zu erzwingen encoded!, können Sie es verwenden encoded ?? ""oder verwenden if let encoded = ....


1
.aphanumerics hat es geschafft, danke! Alle anderen Zeichensätze sind den & nicht entgangen, was zu Problemen bei der Verwendung der Zeichenfolgen als get-Parameter führte.
Dion

14

Alles ist gleich

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

// test%2Ftest

Sie haben kein .bridgeToOvjectiveC()zweites Argument und nicht erhalten "Kann den Typ 'CFString!' Des Ausdrucks nicht konvertieren. um 'CFString!' "einzugeben?
Kreiri

@Kreiri Warum wird es benötigt? Sowohl der Spielplatz als auch REPL sind mit meinem Code zufrieden.
Bryan Chen

Meine sind nicht: / (Beta 2)
Kreiri

1
Dies ist eine bessere Antwort, da das & korrekt codiert wird.
Sam

13

Swift 4:

Dies hängt von den Codierungsregeln ab, die von Ihrem Server befolgt werden.

Apple bietet diese Klassenmethode an, meldet jedoch nicht, welcher Art von RCF-Protokoll es folgt.

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

Wenn Sie diesem nützlichen Tool folgen, sollten Sie die Codierung dieser Zeichen für Ihre Parameter garantieren:

  • $ (Dollarzeichen) wird zu% 24
  • & (Kaufmännisches Und) wird zu% 26
  • + (Plus) wird zu% 2B
  • , (Komma) wird% 2C
  • : (Doppelpunkt) wird% 3A
  • ;; (Semikolon) wird zu% 3B
  • = (Gleich) wird zu% 3D
  • ? (Fragezeichen) wird% 3F
  • @ (Commercial A / At) wird zu% 40

Mit anderen Worten, wenn Sie über die URL-Codierung sprechen, sollten Sie das RFC 1738-Protokoll befolgen .

Und Swift behandelt zum Beispiel nicht die Codierung des + Zeichens , aber es funktioniert gut mit diesen drei @ :? Zeichen.

Um jeden Ihrer Parameter korrekt zu codieren, reicht die .urlHostAllowedOption nicht aus. Sie sollten auch die Sonderzeichen hinzufügen, wie zum Beispiel:

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

Hoffe, dies hilft jemandem, der verrückt wird, diese Informationen zu suchen.


Ihre Implementierung ist völlig falsch. Wie würde ein Parameter "věž" codiert?
Marián Černý

13

Swift 4 (nicht getestet - bitte kommentieren Sie, ob es funktioniert oder nicht. Danke @sumizome für den Vorschlag)

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

Swift 3

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

Swift 2.2 (Ausleihen bei Zaph und Korrektur von URL-Abfrageschlüssel- und Parameterwerten)

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

Beispiel:

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"

Dies ist eine kürzere Version von Bryan Chens Antwort. Ich würde vermuten, urlQueryAlloweddass dies die Steuerzeichen zulässt, durch die dies in Ordnung ist, es sei denn, sie sind Teil des Schlüssels oder Werts in Ihrer Abfragezeichenfolge. An diesem Punkt müssen sie maskiert werden.


2
Ich mag die Swift 3-Lösung, aber sie funktioniert in Swift 4 nicht für mich: "Mutierendes Mitglied kann nicht für unveränderlichen Wert verwendet werden: 'urlQueryAllowed' ist eine Get-Only-Eigenschaft".
Marián Černý

@ MariánČerný mach das CharacterSet einfach veränderlich (mit var) und rufe .removees dann in einem zweiten Schritt auf.
Sumizome

Ich glaube, diese und die meisten anderen Lösungen haben Probleme, wenn die Methode zweimal angewendet wird, z. B. wenn eine URL mit codierten Parametern in die Parameter einer anderen URL aufgenommen wird.
FD_

@FD_ weißt du oder hast du nur eine Ahnung? Kannst du damit experimentieren und zurück posten? Wäre gut, diese Informationen aufzunehmen, wenn ja. Danke dir.
AJP

@AJP Ich habe gerade alle deine Schnipsel getestet. Swift 3 und 4 funktionieren einwandfrei, aber die für Swift 2.2 codiert% 20 nicht richtig als% 2520.
FD_

7

Swift 4.2

Eine schnelle einzeilige Lösung. Ersetzen Sie originalStringdurch den String, den Sie codieren möchten.

var encodedString = originalString.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]{} ").inverted)

Online-Spielplatz-Demo


Dies funktionierte dank: Sie können überprüfen und versuchen, Ergebnisse zu dekodieren und zu kodieren. urldecoder.org
Rakshitha Muranga Rodrigo

4

Ich brauchte das selbst und schrieb eine String-Erweiterung, die sowohl URLEncoding-Strings als auch das häufigere Endziel ermöglicht, ein Parameterwörterbuch in URL-Parameter im "GET" -Stil zu konvertieren:

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
    }
}

Genießen!


2
Dies kodiert das '&' nicht. Wenn Sie ein '&' in einem Parameter verwenden, wird der Querystring erhöht
Sam

Dies ist falsch, es codiert nicht &oder =in Parametern. Überprüfen Sie stattdessen meine Lösung.
Marián Černý

2

Dieser arbeitet für mich.

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
}

Ich habe die obige Funktion über diesen Link gefunden: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/ .


1

let Url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")


0

SWIFT 4.2

Manchmal geschah dies nur, weil im Slug ODER ohne URL-Codierung Platz für Parameter vorhanden ist, die über die API-URL übertragen werden.

let myString = self.slugValue
                let csCopy = CharacterSet(bitmapRepresentation: CharacterSet.urlPathAllowed.bitmapRepresentation)
                let escapedString = myString!.addingPercentEncoding(withAllowedCharacters: csCopy)!
                //always "info:hello%20world"
                print(escapedString)

HINWEIS: Vergessen Sie nicht, etwas zu erkunden bitmapRepresentation.


0

Das funktioniert bei mir in Swift 5 . Der Anwendungsfall besteht darin, eine URL aus der Zwischenablage oder ähnlichem zu übernehmen, die möglicherweise bereits maskierte Zeichen enthält, aber auch Unicode-Zeichen enthält, die URLComponentsoder verursachen könnenURL(string:) fehlschlagen können.

Erstellen Sie zunächst einen Zeichensatz, der alle URL-zulässigen Zeichen enthält:

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
    }
}

Erweitern Sie Stringals Nächstes eine Methode zum Codieren von URLs:

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
    }

}

Welches kann getestet werden wie:

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)

Wert von urlam Ende: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

Beachten Sie, dass sowohl der Abstand %20als auch der +Abstand erhalten bleiben, Unicode-Zeichen codiert werden, das %20im Original urlTextnicht doppelt codiert ist und der Anker (Fragment oder #) erhalten bleibt.

Bearbeiten: Überprüfen Sie nun die Gültigkeit jeder Komponente.


0

Für Swift 5 zur Endcode-Zeichenfolge

func escape(string: String) -> String {
    let allowedCharacters = string.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: ":=\"#%/<>?@\\^`{|}").inverted) ?? ""
    return allowedCharacters
}

Wie benutzt man ?

let strEncoded = self.escape(string: "http://www.edamam.com/ontologies/edamam.owl#recipe_e2a1b9bf2d996cbd9875b80612ed9aa4")
print("escapedString: \(strEncoded)")

0

Keine dieser Antworten hat bei mir funktioniert. Unsere App stürzte ab, als eine URL nicht englische Zeichen enthielt.

 let unreserved = "-._~/?%$!:"
 let allowed = NSMutableCharacterSet.alphanumeric()
     allowed.addCharacters(in: unreserved)

 let escapedString = urlString.addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)

Abhängig von den Parametern, die Sie ausführen möchten, möchten Sie möglicherweise nur Ihren eigenen Zeichensatz erstellen. Das obige erlaubt englische Zeichen und-._~/?%$!:

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.