Dies funktioniert für mich in Swift 5. Das Anwendungsbeispiel besteht darin, eine URL aus der Zwischenablage oder ähnlichem zu übernehmen, die bereits maskierte Zeichen enthalten kann, aber auch Unicode-Zeichen, die dazu führen könnten, dass URLComponents
oder URL(string:)
fehlschlagen.
Zunächst wird ein Zeichensatz erstellt, der alle für URLs zulässigen Zeichen enthält:
extension CharacterSet {
/// Zeichen, die mindestens in einem Teil einer URL gültig sind.
///
/// Diese Zeichen sind nicht in ALLEN Teilen einer URL erlaubt; jeder Teil hat unterschiedliche Anforderungen. Dieser Satz ist hilfreich, um nach Unicode-Zeichen zu suchen, die vor der Durchführung eines Gültigkeitschecks für einzelne URL-Komponenten Prozent-codiert werden müssen.
static var urlAllowedCharacters: CharacterSet {
// Beginne mit Hashtag, der in keinem Satz enthalten ist
var characters = CharacterSet(charactersIn: "#")
// Alle für URLs zulässigen Zeichen
characters.formUnion(.urlUserAllowed)
characters.formUnion(.urlPasswordAllowed)
characters.formUnion(.urlHostAllowed)
characters.formUnion(.urlPathAllowed)
characters.formUnion(.urlQueryAllowed)
characters.formUnion(.urlFragmentAllowed)
return characters
}
}
Anschließend wird String
erweitert um eine Methode zum Codieren von URLs:
extension String {
/// Wandelt eine Zeichenfolge in eine Prozent-codierte URL um, einschließlich Unicode-Zeichen.
///
/// - Gibt zurück: Eine codierte URL, wenn alle Schritte erfolgreich sind, andernfalls nil.
func encodedUrl() -> URL? {
// Entferne vorhandene Codierung,
guard let decodedString = self.removingPercentEncoding,
// kodiere alle Unicode-Zeichen, damit URLComponents nicht scheitert,
let unicodeEncodedString = decodedString.addingPercentEncoding(withAllowedCharacters: .urlAllowedCharacters),
// zerlege in Komponenten, um die richtige Codierung für jeden Teil zu verwenden,
let components = URLComponents(string: unicodeEncodedString),
// und re-kodiere, um die Dekodierung wieder rückgängig zu machen, während fehlende Zeichen kodiert werden.
let percentEncodedUrl = components.url else {
// Kodierung fehlgeschlagen
return nil
}
return percentEncodedUrl
}
}
Das kann getestet werden wie folgt:
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 url
am 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 die Leerzeichen %20
als auch +
erhalten bleiben, Unicode-Zeichen codiert sind, das %20
im ursprünglichen urlText
nicht doppelt codiert wird und das Ankerzeichen (Fragment oder #
) erhalten bleibt.
Bearbeitung: Überprüfung der Gültigkeit jeder Komponente.