Risposte:
Sfortunatamente, stringByAddingPercentEscapesUsingEncoding
non funziona sempre al 100%. Codifica caratteri non URL ma lascia da soli i caratteri riservati (come barra /
e commerciale &
). Apparentemente questo è un bug di cui Apple è a conoscenza, ma dal momento che non l'hanno ancora risolto, sto usando questa categoria per url-codificare una stringa:
@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;
}
Usato così:
NSString *urlEncodedString = [@"SOME_URL_GOES_HERE" urlencode];
// Or, with an already existing string:
NSString *someUrlString = @"someURL";
NSString *encodedUrlStr = [someUrlString urlencode];
Questo funziona anche:
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8 );
Qualche buona lettura sull'argomento:
La percentuale di iPhone Objective-c codifica una stringa?
Codifica Objective-C e 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 /
Questo potrebbe essere utile
NSString *sampleUrl = @"http://www.google.com/search.jsp?params=Java Developer";
NSString* encodedUrl = [sampleUrl stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
Per iOS 7+, il modo consigliato è:
NSString* encodedUrl = [sampleUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
È possibile scegliere il set di caratteri consentito in base ai requisiti del componente URL.
-stringByAddingPercentEncodingWithAllowedCharacters:
invece, che utilizza sempre la codifica UTF-8 consigliata e che codifica per un componente o sottocomponente URL specifico poiché ciascun componente o sottocomponente URL ha regole diverse per quali caratteri sono validi."
Sono state aggiunte nuove API da quando è stata selezionata la risposta; Ora puoi usare NSURLUtilities. Poiché parti diverse di URL consentono caratteri diversi, utilizzare il set di caratteri applicabile. L'esempio seguente codifica per l'inclusione nella stringa di query:
encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
Per convertire specificamente "&", devi rimuoverlo dal set di query dell'URL o utilizzare un set diverso, poiché "&" è consentito in una query URL:
NSMutableCharacterSet *chars = NSCharacterSet.URLQueryAllowedCharacterSet.mutableCopy;
[chars removeCharactersInRange:NSMakeRange('&', 1)]; // %26
encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:chars];
NSMakeRange('&', 1)
non funziona in Swift, perché Swift non consente la conversione int di char senza hack. Per utilizzare questa soluzione nel codice Swift, utilizzare removeCharactersInString("&")
invece di.removeCharactersInRange(...)
Esempio Swift 2.0 (iOS 9 compatibile)
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
}
}
aggiornamento iOS 7
NSString *encode = [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *decode = [encode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Ho scelto di utilizzare la CFURLCreateStringByAddingPercentEscapes
chiamata come indicato dalla risposta accettata, tuttavia nella versione più recente di XCode (e IOS), si è verificato un errore, quindi ho usato invece il seguente:
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));
Prova a usare il stringByAddingPercentEncodingWithAllowedCharacters
metodo con[NSCharacterSet URLUserAllowedCharacterSet]
esso coprirà tutti i casi
Obiettivo C
NSString *value = @"Test / Test";
value = [value stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLUserAllowedCharacterSet]];
veloce
var value = "Test / Test"
value.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLUserAllowedCharacterSet())
Produzione
Test%20%2F%20Test
Dopo aver letto tutte le risposte per questo argomento e quella ( sbagliata ) accettata, voglio aggiungere il mio contributo.
SE l'obiettivo è iOS7 +, e nel 2017 dovrebbe essere molto difficile offrire compatibilità con iOS 8, poiché il modo migliore, thread thread sicuro, veloce, e il pieno supporto UTF-8 per farlo è:
(Codice obiettivo 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
Ciò estenderà NSString, escluderà i caratteri vietati RFC, supporterà i caratteri UTF-8 e ti consentirà di usare cose come:
NSString *myusername = "I'm[evil]&want(to)break!!!$->àéìòù";
NSLog(@"Source: %@ -> Dest: %@", myusername, [myusername urlencode]);
Che verrà stampato sulla tua console di debug:
Fonte: I'm [evil] & want (to) break !!! $ -> àéìòù -> Dest: I% 27m% 5Bevil% 5D% 26want% 28to% 29break% 21% 21% 21% 24-% 3E% C3 % A0% C3% A9% C3% AC% C3% B2% C3% B9
... nota anche l'uso di dispatch_once per evitare inizializzazioni multiple in ambienti multithread.
Ecco un approccio flessibile pronto per la produzione in 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
Utilizzare i componenti NSURLC per codificare i parametri 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/
Questo codice mi ha aiutato a codificare caratteri speciali
NSString* encPassword = [password stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];
codice rapido basato sulla risposta objc di chown in questo thread.
extension String {
func urlEncode() -> String {
return CFURLCreateStringByAddingPercentEscapes(
nil,
self,
nil,
"!*'();:@&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)
}
}
In Swift 3 , prova di seguito:
let stringURL = "YOUR URL TO BE ENCODE";
let encodedURLString = stringURL.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(encodedURLString)
Poiché, stringByAddingPercentEscapesUsingEncoding
codifica caratteri non URL ma lascia i caratteri riservati (come !*'();:@&=+$,/?%#[]
), è possibile codificare l'URL come il seguente codice:
let stringURL = "YOUR URL TO BE ENCODE";
let characterSetTobeAllowed = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted)
if let encodedURLString = stringURL.addingPercentEncoding(withAllowedCharacters: characterSetTobeAllowed) {
print(encodedURLString)
}
Il consiglio di Apple, nelle note di rilascio della 10.11, è:
Se devi codificare in percentuale una stringa URL intera, puoi utilizzare questo codice per codificare un NSString destinato ad essere un URL (in urlStringToEncode):
NSString *percentEncodedURLString =
[[NSURL URLWithDataRepresentation:[urlStringToEncode dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil] relativeString];
Nel mio caso in cui l'ultimo componente era costituito da lettere arabe, ho fatto quanto segue 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;
}
}
utilizzo:
let stringURL = "http://xxx.dev.com/endpoint/nonLatinCharacters"
if let encodedStringURL = stringURL.encodeUTF8() {
if let url = NSURL(string: encodedStringURL) {
...
}
}
-(NSString *)encodeUrlString:(NSString *)string {
return CFBridgingRelease(
CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge CFStringRef)string,
NULL,
CFSTR("!*'();:@&=+$,/?%#[]"),
kCFStringEncodingUTF8)
);
}
secondo il seguente blog
Così tante risposte ma non ha funzionato per me, quindi ho provato quanto segue:
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...
}
Spero che possa aiutare qualcuno. Grazie
Per i singoli parametri di query codificati in forma www, ho creato una categoria su NSString:
- (NSString*)WWWFormEncoded{
NSMutableCharacterSet *chars = NSCharacterSet.alphanumericCharacterSet.mutableCopy;
[chars addCharactersInString:@" "];
NSString* encodedString = [self stringByAddingPercentEncodingWithAllowedCharacters:chars];
encodedString = [encodedString stringByReplacingOccurrencesOfString:@" " withString:@"+"];
return encodedString;
}
// Questo è senza test
NSMutableCharacterSet* set = [[NSCharacterSet alphanumericCharacterSet] mutableCopy];
[set addCharactersInString:@"-_.~"];
NSString *encode = [test stringByAddingPercentEncodingWithAllowedCharacters:set];
Ho riscontrato un problema simile passando stringhe complesse come parametro POST. Le mie stringhe possono contenere caratteri asiatici, spazi, virgolette e tutti i tipi di caratteri speciali. La soluzione che ho trovato alla fine è stata quella di convertire la mia stringa nella serie di unicode corrispondente, ad esempio "Hu0040Hu0020Hu03f5 ...." utilizzando [NSString stringWithFormat: @ "Hu% 04x", [string characterAtIndex: i]] per ottenere l'Unicode da ciascuno carattere nella stringa originale. Lo stesso può essere fatto in Java.
Questa stringa può essere tranquillamente passata come parametro POST.
Sul lato server (PHP), cambio tutta la "H" in "\" e passo la stringa risultante a json_decode. Il passaggio finale consiste nell'evitare le virgolette singole prima di archiviare la stringa in MySQL.
In questo modo posso memorizzare qualsiasi stringa UTF8 sul mio server.
Questo funziona per me.
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
}
Ho trovato la funzione sopra da questo link: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/
È inoltre possibile utilizzare questa funzione con estensione rapida. Per favore fatemi sapere se c'è qualche problema.