我如何URL编码字符串


Answers:


291

不幸的是,stringByAddingPercentEscapesUsingEncoding并非总是100%有效。它对非URL字符进行编码,但保留的保留字符(例如斜杠/和&符&)则单独保留。显然,这是Apple意识到的错误,但是由于他们尚未修复它,因此我一直在使用此类别对字符串进行url编码:

@implementation NSString (NSString_Extended)

- (NSString *)urlencode {
    NSMutableString *output = [NSMutableString string];
    const unsigned char *source = (const unsigned char *)[self UTF8String];
    int sourceLen = strlen((const char *)source);
    for (int i = 0; i < sourceLen; ++i) {
        const unsigned char thisChar = source[i];
        if (thisChar == ' '){
            [output appendString:@"+"];
        } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' || 
                   (thisChar >= 'a' && thisChar <= 'z') ||
                   (thisChar >= 'A' && thisChar <= 'Z') ||
                   (thisChar >= '0' && thisChar <= '9')) {
            [output appendFormat:@"%c", thisChar];
        } else {
            [output appendFormat:@"%%%02X", thisChar];
        }
    }
    return output;
}

像这样使用:

NSString *urlEncodedString = [@"SOME_URL_GOES_HERE" urlencode];

// Or, with an already existing string:
NSString *someUrlString = @"someURL";
NSString *encodedUrlStr = [someUrlString urlencode];

这也适用:

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

关于该主题的一些不错的阅读:

Objective-c iPhone百分比编码字符串吗?
Objective-C和Swift URL编码

http://cybersam.com/programming/proper-url-percent-encoding-in-ios
https://devforums.apple.com/message/15674#15674 http://simonwoodside.com/weblog/2009/4/ 22 / how_to_really_url_encode /


12
到底为什么要使用这样一个复杂的类别,而不是直接下拉到CFURLCreateStringByAddingPercentEscapes(),您可以在其中明确指定要始终转义的字符。
莉莉·巴拉德

8
@KevinBallard,因为CF函数适用于包含模型(“转义这些字符”),并且通常您希望使用专用模型(“转义这些字符外的所有字符”)
Dave DeLong


31
@DaveDeLong那可能是我得到的地方。大约一年以来,它一直是我所有项目中的标准类别,所以我想您可能是原始来源!我已经对措辞进行了编辑,因此似乎我并没有因为写它而受到赞誉)。
chown

4
为什么?如果(thisChar ==''){[输出appendString:@“ +”]; }如果没有它,它将像我期望的那样用%20编码空格
Chris Stephens

127

这可能会有所帮助

NSString *sampleUrl = @"http://www.google.com/search.jsp?params=Java Developer";
NSString* encodedUrl = [sampleUrl stringByAddingPercentEscapesUsingEncoding:
 NSUTF8StringEncoding];

对于iOS 7+,推荐的方法是:

NSString* encodedUrl = [sampleUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

您可以根据URL组件的要求选择允许的字符集。


7
这也无法正确编码参数定界符,例如“&”,“?” 在将内容传递到API的情况下。
本·拉赫曼

“&”不是URL查询字符串参数的有效字符。请尝试使用“&amp;” 代替。
Nishant

1
“ stringByAddingPercentEscapesUsingEncoding已弃用”请-stringByAddingPercentEncodingWithAllowedCharacters:改用,它始终使用建议的UTF-8编码,并且为特定的URL组件或子组件编码,因为每个URL组件或子组件对于有效字符均具有不同的规则。
米希尔·奥扎

89

自从选择答案以来,已经添加了新的API。您现在可以使用NSURLUtilities。由于URL的不同部分允许使用不同的字符,因此请使用适用的字符集。下面的示例编码为包含在查询字符串中:

encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];

要专门转换“&”,您需要将其从url查询集中删除或使用其他设置,因为URL查询中允许使用“&”:

NSMutableCharacterSet *chars = NSCharacterSet.URLQueryAllowedCharacterSet.mutableCopy;
[chars removeCharactersInRange:NSMakeRange('&', 1)]; // %26
encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:chars];

1
我花了一段时间才弄清楚“使用NSURLUtilities”的含义-但现在我看到那是NSString类别的名称,Apple在其中定义了iOS 7和OS X 10.9中的这种新方法。
Richard Venable

1
这里有一个更详尽的答案,例如:stackoverflow.com/a/20271177/456366
Richard Venable 2014年

对。在发布的新API列表中,它也被列为NSURLUtilities。
Peter DeWeese 2014年

当然,查询字符串中允许使用“&”,因此我将使用Richard的链接来编辑答案。
Peter DeWeese 2014年

3
NSMakeRange('&', 1)在Swift中不起作用,因为Swift不允许在没有黑客的情况下将char转换为int。要使用SWIFT代码这个解决方案,使用removeCharactersInString("&")替代.removeCharactersInRange(...)
cbh2000

16

Swift 2.0示例(与iOS 9兼容)

extension String {

  func stringByURLEncoding() -> String? {

    let characters = NSCharacterSet.URLQueryAllowedCharacterSet().mutableCopy() as! NSMutableCharacterSet

    characters.removeCharactersInString("&")

    guard let encodedString = self.stringByAddingPercentEncodingWithAllowedCharacters(characters) else {
      return nil
    }

    return encodedString

  }

}

2
@AlecThomas您似乎必须跳了几圈才能到达这里,这就是为什么最好在扩展中隐藏它
Oliver Atkinson

@OliverAtkinson-对我来说,Int(String(Character(“&”)))将返回nil,这应该是正确的。而是character.removeCharactersInString(“&”)。

14

ios 7更新

NSString *encode = [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

NSString *decode = [encode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

这是不准确的。您将希望以不同的方式对URL的不同部分进行转义。stackoverflow.com/questions/3423545/…–
史蒂夫·摩泽

实际上,它取决于服务器上允许的字符,在此示例中,我使用的服务器上仅允许使用字母数字字符集,您可以将其更改为特定字符以满足您的需求。
Underdog

1
该问题询问有关编码“&”字符的问题。
史蒂夫·摩瑟

8

我选择使用已CFURLCreateStringByAddingPercentEscapes接受答案给出的呼叫,但是在最新版本的XCode(和IOS)中,它导致了错误,因此改用以下代码:

NSString *apiKeyRaw = @"79b|7Qd.jW=])(fv|M&W0O|3CENnrbNh4}2E|-)J*BCjCMrWy%dSfGs#A6N38Fo~";

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

它不是编码空间。示例@“ string string”和@“ string&string”正确编码。请让我知道您的输入。
Yogesh Lolusare 2014年

2
我花了解决,这是否定时期,我拒绝相信框架犯规包含名为类似于此动作不绕搞乱“进行urlencode”的东西的时候..最
dancl

6

尝试将stringByAddingPercentEncodingWithAllowedCharacters方法与[NSCharacterSet URLUserAllowedCharacterSet]将涵盖所有情况

目标C

NSString *value = @"Test / Test";
value = [value stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLUserAllowedCharacterSet]];

迅速

var value = "Test / Test"
value.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLUserAllowedCharacterSet())

输出量

Test%20%2F%20Test


6

阅读有关该主题的所有答案和(错误接受),我想添加我的贡献。

如果目标是iOS7 +,并且在2017年XCode很难在iOS8下提供兼容性,那么最好的方法是线程安全,快速,而AMD将提供完整的UTF-8支持是:

(目标C代码)

@implementation NSString (NSString_urlencoding)

- (NSString *)urlencode {
    static NSMutableCharacterSet *chars = nil;
    static dispatch_once_t pred;

    if (chars)
        return [self stringByAddingPercentEncodingWithAllowedCharacters:chars];

    // to be thread safe
    dispatch_once(&pred, ^{
        chars = NSCharacterSet.URLQueryAllowedCharacterSet.mutableCopy;
        [chars removeCharactersInString:@"!*'();:@&=+$,/?%#[]"];
    });
    return [self stringByAddingPercentEncodingWithAllowedCharacters:chars];
}
@end

这将扩展NSString,将排除RFC禁止的字符,支持UTF-8字符,并允许您使用以下内容:

NSString *myusername = "I'm[evil]&want(to)break!!!$->àéìòù";
NSLog(@"Source: %@ -> Dest: %@", myusername, [myusername urlencode]);

这将在您的调试控制台上打印:

来源:我很想破!!! $->àéìòù->目的地:I%27m%5Bevil%5D%26want%28to%29break%21%21%21%24-%3E%C3 %A0%C3%A9%C3%AC%C3%B2%C3%B9

...还要注意使用dispatch_once以避免在多线程环境中进行多次初始化。


5

这是Swift 5.x中可用于生产的灵活方法:

public extension CharacterSet {

    static let urlQueryParameterAllowed = CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "&?"))

    static let urlQueryDenied           = CharacterSet.urlQueryAllowed.inverted()
    static let urlQueryKeyValueDenied   = CharacterSet.urlQueryParameterAllowed.inverted()
    static let urlPathDenied            = CharacterSet.urlPathAllowed.inverted()
    static let urlFragmentDenied        = CharacterSet.urlFragmentAllowed.inverted()
    static let urlHostDenied            = CharacterSet.urlHostAllowed.inverted()

    static let urlDenied                = CharacterSet.urlQueryDenied
        .union(.urlQueryKeyValueDenied)
        .union(.urlPathDenied)
        .union(.urlFragmentDenied)
        .union(.urlHostDenied)


    func inverted() -> CharacterSet {
        var copy = self
        copy.invert()
        return copy
    }
}



public extension String {
    func urlEncoded(denying deniedCharacters: CharacterSet = .urlDenied) -> String? {
        return addingPercentEncoding(withAllowedCharacters: deniedCharacters.inverted())
    }
}

用法示例:

print("Hello, World!".urlEncoded()!)
print("You&Me?".urlEncoded()!)
print("#Blessed 100%".urlEncoded()!)
print("Pride and Prejudice".urlEncoded(denying: .uppercaseLetters)!)

输出:

Hello,%20World!
You%26Me%3F
%23Blessed%20100%25
%50ride and %50rejudice

请附上注释解释你的downvotes的原因,所以我知道如何写在未来🙂一个更好的答案
本Leggiero

4

使用NSURLComponents编码HTTP GET参数:

    var urlComponents = NSURLComponents(string: "https://www.google.de/maps/")!
    urlComponents.queryItems = [
        NSURLQueryItem(name: "q", value: String(51.500833)+","+String(-0.141944)),
        NSURLQueryItem(name: "z", value: String(6))
    ]
    urlComponents.URL     // returns https://www.google.de/maps/?q=51.500833,-0.141944&z=6

http://www.ralfebert.de/snippets/ios/encoding-nsurl-get-parameters/


1
它不对“&”号,斜线或分号进行编码。
法比奥·奥利维拉

4

此代码帮助我编码特殊字符

NSString* encPassword = [password stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];

3

在此线程中基于chown的objc答案的快速代码。

extension String {
    func urlEncode() -> String {
        return CFURLCreateStringByAddingPercentEscapes(
            nil,
            self,
            nil,
            "!*'();:@&=+$,/?%#[]",
            CFStringBuiltInEncodings.UTF8.rawValue
        )
    }
}

4
此功能已在iOS 9中弃用:(
Oliver Atkinson

3

Swift 3中,请尝试以下操作:

let stringURL = "YOUR URL TO BE ENCODE";
let encodedURLString = stringURL.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(encodedURLString)

由于对stringByAddingPercentEscapesUsingEncoding非URL字符进行编码,但保留了保留字符(如!*'();:@&=+$,/?%#[]),因此您可以使用以下代码对url进行编码:

let stringURL = "YOUR URL TO BE ENCODE";
let characterSetTobeAllowed = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted)
if let encodedURLString = stringURL.addingPercentEncoding(withAllowedCharacters: characterSetTobeAllowed) {
    print(encodedURLString)
}

2

迅速3:

// exclude alpha and numeric == "full" encoding
stringUrl = stringUrl.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!;

// exclude hostname and symbols &,/ and etc
stringUrl = stringUrl.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!;

2

在10.11发行说明中,Apple的建议是:

如果您需要对整个URL字符串进行百分比编码,则可以使用以下代码对要用作URL的NSString进行编码(在urlStringToEncode中):

NSString *percentEncodedURLString =
  [[NSURL URLWithDataRepresentation:[urlStringToEncode dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil] relativeString];

似乎不起作用,像&之类的字符仍然单独存在
kjyv

1

对于最后一个成分是阿拉伯字母的情况,我在以下方面进行了以下操作Swift 2.2

extension String {

 func encodeUTF8() -> String? {

    //If I can create an NSURL out of the string nothing is wrong with it
    if let _ = NSURL(string: self) {

        return self
    }

    //Get the last component from the string this will return subSequence
    let optionalLastComponent = self.characters.split { $0 == "/" }.last


    if let lastComponent = optionalLastComponent {

        //Get the string from the sub sequence by mapping the characters to [String] then reduce the array to String
        let lastComponentAsString = lastComponent.map { String($0) }.reduce("", combine: +)


        //Get the range of the last component
        if let rangeOfLastComponent = self.rangeOfString(lastComponentAsString) {
            //Get the string without its last component
            let stringWithoutLastComponent = self.substringToIndex(rangeOfLastComponent.startIndex)


            //Encode the last component
            if let lastComponentEncoded = lastComponentAsString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet()) {


            //Finally append the original string (without its last component) to the encoded part (encoded last component)
            let encodedString = stringWithoutLastComponent + lastComponentEncoded

                //Return the string (original string/encoded string)
                return encodedString
            }
        }
    }

    return nil;
}
}

用法:

let stringURL = "http://xxx.dev.com/endpoint/nonLatinCharacters"

if let encodedStringURL = stringURL.encodeUTF8() {

    if let url = NSURL(string: encodedStringURL) {

      ...
    }

} 

1
-(NSString *)encodeUrlString:(NSString *)string {
  return CFBridgingRelease(
                    CFURLCreateStringByAddingPercentEscapes(
                        kCFAllocatorDefault,
                        (__bridge CFStringRef)string,
                        NULL,
                        CFSTR("!*'();:@&=+$,/?%#[]"),
                        kCFStringEncodingUTF8)
                    );
}

根据以下博客


但是在iOS 9中已弃用。为此更新的代码是什么?
Sujit Nachan

1

这么多答案,但对我不起作用,因此我尝试了以下操作:

fun simpleServiceCall(for serviceUrl: String, appendToUrl: String) { 
    let urlString: String = serviceUrl + appendToUrl.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!     

    let finalUrl = URL(string: urlString)!

    //continue to execute your service call... 
}

希望它将对某人有所帮助。谢谢


0

对于各个www表单编码的查询参数,我在NSString上创建了一个类别:

- (NSString*)WWWFormEncoded{
     NSMutableCharacterSet *chars = NSCharacterSet.alphanumericCharacterSet.mutableCopy;
     [chars addCharactersInString:@" "];
     NSString* encodedString = [self stringByAddingPercentEncodingWithAllowedCharacters:chars];
     encodedString = [encodedString stringByReplacingOccurrencesOfString:@" " withString:@"+"];
     return encodedString;
}

0

//这是未经测试

NSMutableCharacterSet* set = [[NSCharacterSet alphanumericCharacterSet] mutableCopy];
[set addCharactersInString:@"-_.~"];
NSString *encode = [test stringByAddingPercentEncodingWithAllowedCharacters:set];

0

我遇到了类似的问题,将复杂的字符串作为POST参数传递。我的字符串可以包含亚洲字符,空格,引号和各种特殊字符。我最终找到的解决方案是使用[NSString stringWithFormat:@“ Hu%04x”,[string characterAtIndex:i]]将我的字符串转换为匹配的unicode系列,例如“ Hu0040Hu0020Hu03f5 ....”,以便从每个字符串中获取Unicode。原始字符串中的字符。在Java中也可以这样做。

该字符串可以安全地作为POST参数传递。

在服务器端(PHP),我将所有的“ H”更改为“ \”,并将结果字符串传递给json_decode。最后一步是在将字符串存储到MySQL中之前对单引号进行转义。

这样,我可以在服务器上存储任何UTF8字符串。


0

这个正在为我工​​作。

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/

您也可以将此功能与swift扩展一起使用。请让我知道是否有任何问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.