Swift-エンコードURL


295

このような文字列をエンコードすると:

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

スラッシュをエスケープしません/

私はこのObjective Cコードを検索して見つけました:

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

URLをエンコードする簡単な方法はありますか?それ以外の場合、Swiftでこれをどのように記述できますか?

回答:


613

スウィフト3

Swift 3には addingPercentEncoding

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

出力:

test%2Ftest

スウィフト1

iOS 7以降には stringByAddingPercentEncodingWithAllowedCharacters

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

出力:

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

出力:

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

6
このコードがこれを実行するのにどれくらいの時間がかかるかについて完全に悩まされている人は他にいませんか?つまり、許可された文字セットを選択しなくても、メソッド名はすでに非常に長くなっています。
thatidiotguy 2014

38
いいえ、短い簡潔なネーミングよりもわかりやすさを優先します。オートコンプリートは痛みを取り除きます。stringByAddingPercentEncodingWithAllowedCharacters()それが何をするかについてほとんど疑いを残しません。「flabbergasted」という単語がどのくらい長いかを考えると興味深いコメントです。
zaph 2014

1
stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())すべての文字を適切にエンコードしないブライアンチェンの答えがより良い解決策です。
フリオガルシア

2
@zaphの&文字セットに追加し URLQueryAllowedCharacterSet、各文字をエンコードしました。iOS 9で確認したところ、バギーのように見えました。@ bryanchenの回答を使用しました。うまくいきました。
Akash Kava

3
以下の答えはIMO を使用URLComponentsURLQueryItemており、よりクリーンです。
アーロンブラジャー2017年

65

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
}

7
他のすべての問題に問題があるため、この回答にはもっと注意が必要です(公平を期すために、それらは当時のベストプラクティスであった可能性があります)。
Asa

4
残念ながら、URLQueryItemは常に正しくエンコードされません。たとえば、Formula+OneにエンコードされFormula+One、にデコードされFormula Oneます。したがって、プラス記号には注意が必要です。
スルタン2018年

37

スウィフト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. 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"

私は最初の解決策を使用しましたが、iOS开发工程师のようにテキストに戻したいです。
Akshay Phulare

2
使用してurlHostAllowed、それはエンコードしないので、間違ったでクエリパラメータを符号化するため?=および+。クエリパラメータをエンコードするときは、パラメータの名前と値を個別に正しくエンコードする必要があります。これは一般的なケースでは機能しません。
スルタン

@Sulthan ..解決策/代替案は見つかりましたかurlHostAllowed
Bharath

@Bharathはい、自分で文字セットを作成する必要があります。たとえば、stackoverflow.com / a / 39767927/669586 または単にを使用しますURLComponents
スルタン

URLComponentsも+文字をエンコードしません。だから、唯一のオプションは、手動でそれを行うことです:CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "+"))
SoftDesigner

36

スウィフト3:

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

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

2
文字列に ``(スペース)を含める必要があります
AJP

1
また、^も含める必要があります
Mani

26

スウィフト4

URLのパラメーターをエンコードするには、.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 ?? ""ますif let encoded = ...


1
.aphanumericsがトリックを行いました、ありがとうございます!他のすべての文字セットは&をエスケープしなかったため、文字列をgetパラメータとして使用するときに問題が発生しました。
Dion

14

すべてが同じです

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

// test%2Ftest

あなたはしませんでした.bridgeToOvjectiveC()2番目の引数と表現の型変換できません」を取得していない『のCFStringを!』「CFString!」と入力するには? "
Kreiri、2014

@Kreiriなぜそれが必要なのですか?遊び場とREPLの両方が私のコードに満足しています。
ブライアンチェン

私のものではありません:/(ベータ2)
Kreiri

1
&を正しくエンコードするため、これはより良い答えです。
サム

13

スウィフト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のエンコーディングをカバーしていませんが、次の3つの@でうまく機能します。チャー。

したがって、各パラメーターを正しくエンコードするには、.urlHostAllowedオプションでは不十分です。たとえば、次のように特殊文字も追加する必要があります。

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

これがクレイジーになった人がこれらの情報を検索するのに役立つことを願っています。


あなたの実装は完全に間違っています。パラメータ「věž」はどのようにエンコードされますか?
マリアンチェルニー

13

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が制御文字を許可していると思いますが、それらがエスケープする必要がある時点でクエリ文字列のキーまたは値の一部を形成しない限り、それは問題ありません。


2
私はSwift 3ソリューションが好きですが、Swift 4では機能しません。「不変の値に変更メンバーを使用できません:「urlQueryAllowed」は取得専用のプロパティです」。
マリアンチェルニー

@MariánČernýは、CharacterSetを(でvar)変更可能に.removeしてから、2番目のステップでそれを呼び出します。
sumizome

これを含む他のほとんどのソリューションには、メソッドを2回適用するとき、たとえばエンコードされたパラメーターを持つURLを別のURLのパラメーターに含めるときに問題があると思います。
FD_

@FD_ご存知ですか、それとも直感がありますか?実験してポストバックできますか?もしそうなら、この情報を含めるとよいでしょう。ありがとうございました。
AJP

@AJP私はすべてのスニペットをテストしました。Swift 3と4は問題なく動作しますが、Swift 2.2の場合は%20を%2520として適切にエンコードしません。
FD_

7

Swift 4.2

迅速な1行ソリューション。originalStringエンコードする文字列に置き換えます。

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

オンライン遊び場デモ


これでうまくいきました。結果を確認してデコードおよびエンコードできます。urldecoder.org
Rakshitha Muranga Rodrigo

4

私自身もこれを必要としていたため、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
    }
}

楽しい!


2
これは「&」記号をエンコードしません。パラメータで「&」を使用すると、クエリ文字列がf ***になります
Sam

これは間違っています。エンコードされない&=、パラメータ内にありません。代わりに私のソリューションを確認してください。
マリアンチェルニー

2

これは私のために働いています。

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/


1

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


0

SWIFT 4.2

時々これは、スラッグにスペースがあるか、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


0

これはSwift 5で私のために働いています。使用例は、すでにエスケープ文字が含まれている可能性があるが、失敗URLComponentsまたはURL(string:)失敗する可能性のあるUnicode文字が含まれているクリップボードなどからURLを取得する場合です。

まず、すべての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
    }
}

次に、StringURLをエンコードするメソッドで拡張します。

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

%20+スペースの両方が保持され、Unicode文字がエンコードさ%20れ、元のurlTextは二重にエンコードされず、アンカー(フラグメントまたは#)が残ることに注意してください。

編集:各コンポーネントの有効性を確認します。


0

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

0

これらの答えはどれもうまくいきませんでした。URLに英語以外の文字が含まれていると、アプリがクラッシュしました。

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

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

実行しようとしていることのパラメータに応じて、独自の文字セットを作成することもできます。上記は英語の文字を許可し、そして-._~/?%$!:

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.