Como codifico uma string em URL


Respostas:


291

Infelizmente, stringByAddingPercentEscapesUsingEncodingnem sempre funciona 100%. Ele codifica caracteres que não são de URL, mas deixa os caracteres reservados (como barra /ee comercial &) sozinhos. Aparentemente, este é um bug que a Apple sabe, mas como eles ainda não o corrigiram, eu tenho usado essa categoria para codificar url uma string:

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

Usado assim:

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

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

Isso também funciona:

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

Algumas boas leituras sobre o assunto:

O objetivo-c por cento do iPhone codifica uma string?
Codificação de URL Objective-C e Swift

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
Por que diabos você usaria uma categoria complicada como essa, em vez de simplesmente ir para CFURLCreateStringByAddingPercentEscapes () , onde você pode especificar explicitamente quais caracteres deseja sempre escapar.
— Lily Ballard

8
@KevinBallard porque a função CF funciona em um modelo inclusivo ( "escapar esses personagens"), e, geralmente, você quer trabalhar em um modelo exclusivo ( "fuga de tudo , exceto esses personagens")
— Dave DeLong


31
@DaveDeLong É aí que eu consegui. Tem sido uma categoria padrão em todos os meus projetos há um ano ou mais, então eu imagino que você possa ter sido a fonte original! Eu editei o texto para que não pareça que estou tentando receber crédito por escrevê-lo).
— Chown

4
Por quê? if (thisChar == '') {[output appendString: @ "+"]; } Com esta se ele vai codificar espaços com% 20 como seria de esperar
— Chris Stephens

127

Isso pode ser útil

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

Para iOS 7 ou superior, a maneira recomendada é:

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

Você pode escolher o conjunto de caracteres permitido conforme o requisito do componente de URL.


7
Isso também não codifica corretamente delimitadores de parâmetros como '&', '?' no caso em que você está transmitindo conteúdo para uma API.
— Ben Lachman

'&' não é um caractere válido para o parâmetro da string de consulta da URL. Por favor, tente usar '& amp;' em vez de.
— Nishant

1
stringByAddingPercentEscapesUsingEncoding DEPRECATED "Use -stringByAddingPercentEncodingWithAllowedCharacters:, em vez disso, que sempre usa a codificação UTF-8 recomendada e que codifica para um componente ou subcomponente específico da URL, pois cada componente ou subcomponente da URL tem regras diferentes para quais caracteres são válidos."
— Mihir Oza

89

Novas APIs foram adicionadas desde que a resposta foi selecionada; Agora você pode usar NSURLUtilities. Como partes diferentes de URLs permitem caracteres diferentes, use o conjunto de caracteres aplicável. O exemplo a seguir codifica para inclusão na cadeia de consulta:

encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];

Para converter especificamente '&', você precisará removê-lo do conjunto de consultas de URL ou usar um conjunto diferente, pois '&' é permitido em uma consulta de URL:

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

1
Demorei um pouco para entender o que você quis dizer com "use NSURLUtilities" - mas agora vejo que esse é o nome da categoria de NSString na qual a Apple definiu esse novo método no iOS 7 e no OS X 10.9.
— Richard Venable 21/03

1
Há uma resposta mais elaborada como este aqui: stackoverflow.com/a/20271177/456366
— Richard Venable

Sim. Também foi listado como NSURLUtilities na lista de novas APIs lançadas.
— Peter DeWeese

É claro que '&' é permitido em uma string de consulta, então eu editarei minha resposta usando o link de Richard.
— Peter DeWeese

3
NSMakeRange('&', 1)não funciona no Swift, porque o Swift não permite a conversão de caracteres para int sem hacks. Para utilizar esta solução em código Swift, use removeCharactersInString("&")em vez de.removeCharactersInRange(...)
— cbh2000

16

Exemplo do Swift 2.0 (compatível com 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 parece que você tem que saltar através de algumas aros para chegar aqui, é por isso que o seu melhor para escondê-lo em uma extensão
— Oliver Atkinson

@OliverAtkinson - para mim Int (String (Character ("&"))) retorna nulo, como deveria. Em vez disso, characters.removeCharactersInString ("&").
— ambientlight

14

atualização ios 7

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

NSString *decode = [encode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

Isso é impreciso. Você deseja escapar de diferentes partes do URL de maneira diferente. stackoverflow.com/questions/3423545/…
— Steve Moser

Na verdade, depende do servidor para caracteres permitidos, aqui no meu exemplo no servidor em que eu estava usando apenas o conjunto de caracteres alfanuméricos permitidos, você pode alterá-lo para caracteres específicos para atender às suas necessidades.
— Underdog

1
A pergunta é feita sobre a codificação do caractere '&'.
— Steve Moser

8

Optei por usar a CFURLCreateStringByAddingPercentEscapeschamada como dada pela resposta aceita, no entanto, na versão mais recente do XCode (e IOS), resultou em um erro, então usei o seguinte:

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

Não está codificando espaço. Exemplo @ "string string" e @ "string & string" estão codificados corretamente. Por favor, deixe-me saber sua opinião sobre o mesmo.
— Yogesh Lolusare

2
para mim a maior parte do tempo gasto resolver este foi o período de negação, onde eu me recusei a acreditar que o does not quadro conter algo chamado semelhante ao 'urlencode' que faz isso sem a andar ..
— dancl

6

Tente usar o stringByAddingPercentEncodingWithAllowedCharactersmétodo com[NSCharacterSet URLUserAllowedCharacterSet] ele irá cobrir todos os casos

Objetivo C

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

rápido

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

Resultado

Test%20%2F%20Test


6

Depois de ler todas as respostas para este tópico e a ( incorreta ) aceita, quero adicionar minha contribuição.

E SE o objetivo for iOS7 +, e em 2017, como o XCode dificulta a compatibilidade com iOS8, a melhor maneira, thread safe, fast, amd terá suporte completo a UTF-8 para fazer isso:

(Código do objetivo 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

Isso estenderá o NSString, excluirá caracteres proibidos RFC, suportará caracteres UTF-8 e permitirá que você use coisas como:

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

Isso será impresso no seu console de depuração:

Fonte: Eu sou [mau] e quero quebrar !!! $ -> àéìòù -> Dest: I% 27m% 5Bevil% 5D% 26want% 28to% 29break% 21% 21% 21% 24-% 3E% C3 % A0% C3% A9% C3% AC% C3% B2% C3% B9

... observe também o uso de dispatch_once para evitar várias inicializações em ambientes multithread.


5

Aqui está uma abordagem flexível pronta para produção no 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())
    }
}

Exemplo de uso:

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

Resultado:

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

Por favor, inclua um comentário explicando o motivo da sua downvotes então eu sei como escrever uma resposta melhor no futuro 🙂
— Ben leggiero

4

Use NSURLComponents para codificar os parâmetros 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
Não codifica e comercial, barras ou ponto e vírgula.
— Fábio Oliveira

4

Esse código me ajudou a codificar caracteres especiais

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

3

código swift baseado na resposta objc do chown neste tópico.

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

4
esta função foi descontinuada no iOS 9 :(
— Oliver Atkinson

3

No Swift 3 , tente abaixo:

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

Como stringByAddingPercentEscapesUsingEncodingcodifica caracteres que não são de URL, mas deixa os caracteres reservados (como !*'();:@&=+$,/?%#[]), você pode codificar o URL como o seguinte código:

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

2

No rápido 3:

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

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

2

O conselho da Apple, nas notas de versão 10.11, é:

Se você precisar codificar em porcentagem uma cadeia de URL inteira, poderá usar esse código para codificar uma NSString destinada a ser uma URL (em urlStringToEncode):

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

não parece trabalho, caracteres como & ainda são deixados sozinhos
— kjyv

1

No meu caso, onde o último componente era letras árabes, fiz o seguinte em 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;
}
}

uso:

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

de acordo com o seguinte blog


Mas está obsoleto no iOS 9. Qual é o código atualizado para isso?
— Sujit Nachan

1

Tantas respostas, mas não funcionaram para mim, então tentei o seguinte:

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

Espero que ajude alguém. obrigado


0

Para parâmetros de consulta individuais codificados em www, criei uma categoria no NSString:

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

0

// Isso é sem teste

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

0

Eu enfrentei um problema semelhante ao passar seqüências complexas como um parâmetro POST. Minhas strings podem conter caracteres asiáticos, espaços, aspas e todos os tipos de caracteres especiais. A solução que encontrei foi converter minha string na série correspondente de unicodes, por exemplo, "Hu0040Hu0020Hu03f5 ...." usando [NSString stringWithFormat: @ "Hu% 04x", [string characterAtIndex: i]] para obter o Unicode de cada caractere na sequência original. O mesmo pode ser feito em Java.

Essa sequência pode ser transmitida com segurança como um parâmetro POST.

No lado do servidor (PHP), altero todo o "H" para "\" e passo a sequência resultante para json_decode. O passo final é escapar aspas simples antes de armazenar a string no MySQL.

Dessa forma, posso armazenar qualquer string UTF8 no meu servidor.


0

Este está trabalhando para mim.

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
}

Encontrei a função acima neste link: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/

Você também pode usar esta função com extensão rápida. Entre em contato se houver algum problema.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.