스위프트-URL 인코딩


295

다음과 같은 문자열을 인코딩하면 :

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

슬래시를 벗어나지 않습니다 /.

이 Objective C 코드를 검색하고 찾았습니다.

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

URL을 인코딩하는 더 쉬운 방법이 있습니까? 그렇지 않은 경우 Swift에서 어떻게 작성합니까?

답변:


613

스위프트 3

스위프트 3에는 addingPercentEncoding

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

산출:

test % 2 최신

스위프트 1

iOS 7 이상에는 stringByAddingPercentEncodingWithAllowedCharacters

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

산출:

test % 2 최신

다음은 유용한 (반전 된) 문자 집합입니다.

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

38
아니요, 간결한 이름 지정에 비해 이해하기 쉽습니다. 자동 완성은 고통을 없애줍니다. stringByAddingPercentEncodingWithAllowedCharacters()그것이하는 일에 대해서는 거의 의심하지 않습니다. "flabbergasted"라는 단어의 길이를 고려한 재미있는 의견.
zaph

1
stringByAddingPercentEncodingWithAllowedCharacters (.URLHostAllowedCharacterSet ()) 모든 문자를 올바르게 인코딩하지 않습니다 Bryan Chen의 답변이 더 나은 솔루션입니다.
Julio Garcia

2
@zaph &문자 세트에 추가 하고 URLQueryAllowedCharacterSet각 문자를 인코딩했습니다. iOS 9에서 확인한 결과 버그가있는 것처럼 보였습니다. @ bryanchen의 답변과 함께갔습니다.
Akash Kava

3
아래의 답변 은 IMO 를 사용 URLComponents하고 URLQueryItem훨씬 깨끗합니다.
Aaron Brager

65

URLComponent를 사용하면 쿼리 문자열을 수동으로 퍼센트 인코딩하지 않아도됩니다.

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. 따라서 더하기 부호를주의하십시오.
Sulthan

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

@Sulthan ..urlHostAllowed
Bharath의

@Bharath 예, stackoverflow.com/a/39767927/669586 과 같이 직접 문자 세트를 작성하거나을 사용해야 URLComponents합니다.
Sulthan

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매개 변수는 강제로 래핑되지 않습니다. 잘못된 유니 코드 문자열의 경우 충돌이 발생할 수 있습니다. String.addingPercentEncoding ()의 반환 값이 선택적인 이유를 참조하십시오 . . 강제로 풀기 대신을 encoded!사용 encoded ?? ""하거나 사용할 수 있습니다 if let encoded = ....


1
.aphanumerics가 트릭을 수행했습니다. 감사합니다! 다른 모든 문자 세트는 &를 이스케이프하지 않아 문자열을 get 매개 변수로 사용할 때 문제가 발생했습니다.
디온

14

모든 것이 동일

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

// test%2Ftest

당신은하지 않았다 .bridgeToOvjectiveC()두 번째 인수와 표현의 형태로 변환 할 수 없습니다 "하지 않았다 'CFString를!' "CFString! '"을 입력하는 방법?
Kreiri

@Kreiri 왜 필요한가요? 놀이터와 REPL 모두 내 코드에 만족합니다.
Bryan Chen

광산은 : / (베타 2)
Kreiri

1
&를 올바르게 인코딩하므로 더 나은 대답입니다.
Sam

13

스위프트 4 :

서버에 따라 인코딩 규칙에 따라 다릅니다.

Apple은이 클래스 방법을 제공하지만 그에 따르는 RCF 프로토콜은보고하지 않습니다.

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

이 유용한 도구사용 하면 매개 변수에 대한 이러한 문자의 인코딩을 보장해야합니다.

  • $ (Dollar Sign)은 % 24가됩니다.
  • & (앰퍼샌드)는 % 26이됩니다.
  • + (플러스)는 % 2B가됩니다
  • , (쉼표)는 % 2C가됩니다
  • : (콜론)은 % 3A가됩니다
  • ; (세미콜론) % 3B가됩니다
  • = (같음) % 3D가 됨
  • ? (물음표) % 3F가됩니다
  • @ (상업 A / At)가 % 40이됩니다.

다시 말해 URL 인코딩에 대해 말하면 RFC 1738 프로토콜 을 따라야 합니다 .

그리고 Swift는 예를 들어 + char의 인코딩을 다루지 않지만 다음 세 가지 @ 와 잘 작동합니다 . 문자.

따라서 각 매개 변수를 올바르게 인코딩하려면 .urlHostAllowed옵션이 충분하지 않으므로 다음과 같이 특수 문자를 추가해야합니다.

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

이것이 미친 사람이 이러한 정보를 검색하는 데 도움이되기를 바랍니다.


구현이 완전히 잘못되었습니다. "věž"매개 변수는 어떻게 인코딩됩니까?
Marián Černý

13

스위프트 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"

이것은 Bryan Chen의 대답보다 짧은 버전입니다. urlQueryAllowed제어 문자가 쿼리 문자열에서 키 또는 값의 일부를 이스케이프 처리하지 않는 한 제어 문자를 허용 하는 것으로 추측 됩니다.


2
Swift 3 솔루션은 마음에 들지만 Swift 4에서는 작동하지 않습니다.
Marián Černý

@ MariánČerný는 CharacterSet를 변경 가능하게 만들고 (with var) .remove두 번째 단계 로 호출 합니다.
sumizome

다른 URL 매개 변수에 인코딩 된 매개 변수가있는 URL을 포함하는 경우와 같이 방법을 두 번 적용 할 때이 솔루션과 대부분의 다른 솔루션에 문제가 있다고 생각합니다.
FD_

@FD_ 당신은 직감이 있습니까? 당신은 그것을 실험하고 다시 게시 할 수 있습니까? 그렇다면이 정보를 포함시키는 것이 좋을 것입니다. 감사합니다.
AJP

@ AJP 방금 모든 스 니펫을 테스트했습니다. Swift 3과 4는 잘 작동하지만 Swift 2.2는 % 20을 % 2520으로 올바르게 인코딩하지 않습니다.
FD_

7

스위프트 4.2

빠른 한 줄 솔루션. 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
'&'부호는 인코딩되지 않습니다. 매개 변수에 '&'를 사용하면 쿼리 문자열이 달라집니다.
Sam

이것은 잘못 &되었거나 인코딩되지 않았 거나 =매개 변수에 없습니다 . 대신 솔루션을 확인하십시오.
Marián Černý

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

스위프트 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:) 실패 입니다.

먼저 모든 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+공백이 모두 유지되고 유니 코드 문자가 인코딩 %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.