Wie codiere ich eine Zeichenfolge per URL?

Antworten:

291

Funktioniert leider stringByAddingPercentEscapesUsingEncodingnicht immer 100%. Es codiert Nicht-URL-Zeichen, lässt jedoch die reservierten Zeichen (wie Schrägstrich /und kaufmännisches Und &) in Ruhe. Anscheinend ist dies ein Fehler , den Apple kennt, aber da er noch nicht behoben wurde, habe ich diese Kategorie verwendet, um eine Zeichenfolge per URL zu codieren:

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

So verwendet:

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

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

Das funktioniert auch:

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

Einige gute Lektüre zu diesem Thema:

Objective-c iPhone Prozent codieren eine Zeichenfolge?
Objective-C- und Swift-URL-Codierung

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 /

chown
quelle
12
Warum um alles in der Welt würden Sie eine komplizierte Kategorie wie diese verwenden, anstatt nur zu CFURLCreateStringByAddingPercentEscapes () zu wechseln , wo Sie explizit angeben können, welchen Zeichen Sie immer entkommen möchten.
Lily Ballard
8
@ KevinBallard, weil die CF-Funktion auf einem inklusiven Modell funktioniert ("Escape diese Zeichen") und Sie normalerweise an einem exklusiven Modell arbeiten möchten ("Escape alles außer diesen Zeichen")
Dave DeLong
31
@ DaveDeLong Vielleicht habe ich es dort bekommen. Es ist seit ungefähr einem Jahr eine Standardkategorie in all meinen Projekten, also stelle ich mir vor, dass Sie die ursprüngliche Quelle waren! Ich habe den Wortlaut so bearbeitet, dass es nicht so aussieht, als würde ich versuchen, das Schreiben zu würdigen.
Chown
4
Warum? if (thisChar == '') {[Ausgabe appendString: @ "+"]; } Ohne dies, wenn es Leerzeichen mit% 20 codieren wird, wie ich es erwarten würde
Chris Stephens
127

Dies könnte hilfreich sein

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

Für iOS 7+ wird empfohlen:

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

Sie können den zulässigen Zeichensatz gemäß den Anforderungen der URL-Komponente auswählen.

Nishant
quelle
7
Dies codiert auch Parameterbegrenzer wie '&', '?' Nicht korrekt. in dem Fall, in dem Sie Inhalte an eine API übergeben.
Ben Lachman
'&' ist kein gültiges Zeichen für den Parameter der URL-Abfragezeichenfolge. Bitte versuchen Sie, '& amp;' stattdessen.
Nishant
1
stringByAddingPercentEscapesUsingEncoding ist DEPRECATED "Verwenden Sie -stringByAddingPercentEncodingWithAllowedCharacters:stattdessen die empfohlene UTF-8-Codierung und die Codierung für eine bestimmte URL-Komponente oder Unterkomponente, da jede URL-Komponente oder Unterkomponente unterschiedliche Regeln für die Gültigkeit der Zeichen hat."
Mihir Oza
89

Seit Auswahl der Antwort wurden neue APIs hinzugefügt. Sie können jetzt NSURLUtilities verwenden. Verwenden Sie den entsprechenden Zeichensatz, da verschiedene Teile von URLs unterschiedliche Zeichen zulassen. Das folgende Beispiel codiert für die Aufnahme in die Abfragezeichenfolge:

encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];

Um '&' spezifisch zu konvertieren, müssen Sie es aus dem URL-Abfragesatz entfernen oder einen anderen Satz verwenden, da '&' in einer URL-Abfrage zulässig ist:

NSMutableCharacterSet *chars = NSCharacterSet.URLQueryAllowedCharacterSet.mutableCopy;
[chars removeCharactersInRange:NSMakeRange('&', 1)]; // %26
encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:chars];
Peter DeWeese
quelle
1
Ich habe eine Weile gebraucht, um herauszufinden, was Sie unter "NSURLUtilities verwenden" verstanden haben - aber jetzt sehe ich, dass dies der Name der Kategorie von NSString ist, in der Apple diese neue Methode in iOS 7 und OS X 10.9 definiert hat.
Richard Venable
1
Es gibt eine ausführlichere Antwort wie diese hier: stackoverflow.com/a/20271177/456366
Richard Venable
Jep. Es wurde auch als NSURLUtilities in der Liste der neu veröffentlichten APIs aufgeführt.
Peter DeWeese
'&' ist natürlich in einer Abfragezeichenfolge zulässig, daher werde ich meine Antwort über Richards Link bearbeiten.
Peter DeWeese
3
NSMakeRange('&', 1)funktioniert in Swift nicht, da Swift nicht zulässt, dass char ohne Hacks konvertiert wird. Um diese Lösung in Swift-Code zu verwenden, verwenden Sie removeCharactersInString("&")anstelle von.removeCharactersInRange(...)
cbh2000
16

Swift 2.0 Beispiel (iOS 9 kompatibel)

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

  }

}
Oliver Atkinson
quelle
2
@AlecThomas Sie scheinen durch ein paar Reifen springen zu müssen, um hierher zu kommen, deshalb ist es besser, es in einer Erweiterung zu verstecken
Oliver Atkinson
@OliverAtkinson - für mich gibt Int (String (Character ("&"))) null zurück, wie es sollte. Stattdessen Zeichen.removeCharactersInString ("&").
Umgebungslicht
14

iOS 7 Update

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

NSString *decode = [encode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Underdog
quelle
Das ist ungenau. Sie möchten verschiedene Teile der URL unterschiedlich maskieren. stackoverflow.com/questions/3423545/…
Steve Moser
Die zulässigen Zeichen hängen tatsächlich von Ihrem Server ab. In meinem Beispiel auf dem Server, auf dem ich nur den zulässigen alphanumerischen Zeichensatz verwendet habe, können Sie diesen in bestimmte Zeichen ändern, um Ihren Anforderungen gerecht zu werden.
Underdog
1
Bei der Frage geht es um die Codierung des Zeichens '&'.
Steve Moser
8

Ich habe mich für die Verwendung des CFURLCreateStringByAddingPercentEscapesAnrufs gemäß der akzeptierten Antwort entschieden. In der neuesten Version von XCode (und IOS) führte dies jedoch zu einem Fehler. Verwenden Sie stattdessen Folgendes:

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));
Mike Purcell
quelle
Es wird kein Speicherplatz codiert. Beispiel @ "string string" und @ "string & string" sind richtig codiert. Bitte teilen Sie mir Ihre Eingabe dazu mit.
Yogesh Lolusare
2
Für mich war die meiste Zeit, die ich damit verbracht habe, dieses Problem zu lösen, die Ablehnungsperiode, in der ich mich geweigert habe zu glauben, dass das Framework nichts enthält, das dem Namen 'Urlencode' ähnelt und dies ohne das Herumspielen tut.
Dancl
6

Versuchen Sie, eine stringByAddingPercentEncodingWithAllowedCharactersMethode zu verwenden [NSCharacterSet URLUserAllowedCharacterSet], die alle Fälle abdeckt

Ziel c

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

schnell

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

Ausgabe

Test%20%2F%20Test

Alex
quelle
6

Nachdem ich alle Antworten zu diesem Thema und die ( falsch ) akzeptierte gelesen habe , möchte ich meinen Beitrag hinzufügen.

WENN das Ziel iOS7 + ist und es 2017 sein sollte, da XCode es wirklich schwierig macht, Kompatibilität unter iOS8 zu liefern, ist der beste Weg, threadsicher, schnell und mit vollständiger UTF-8-Unterstützung, dies zu tun:

(Ziel C-Code)

@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

Dadurch wird NSString erweitert, verbotene RFC-Zeichen ausgeschlossen, UTF-8-Zeichen unterstützt und Sie können Folgendes verwenden:

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

Das wird auf Ihrer Debug-Konsole gedruckt:

Quelle: Ich bin [böse] und möchte brechen !!! $ -> àéìòù -> Ziel: I% 27m% 5Bevil% 5D% 26want% 28to% 29break% 21% 21% 21% 24-% 3E% C3 % A0% C3% A9% C3% AC% C3% B2% C3% B9

... beachten Sie auch die Verwendung von dispatch_once, um Mehrfachinitialisierungen in Multithread-Umgebungen zu vermeiden.

gabry
quelle
5

Hier ist ein produktionsbereiter flexibler Ansatz 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())
    }
}

Anwendungsbeispiel:

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

Ausgabe:

Hello,%20World!
You%26Me%3F
%23Blessed%20100%25
%50ride and %50rejudice
Ben Leggiero
quelle
Bitte fügen Sie einen Kommentar hinzu, in dem der Grund für Ihre Abstimmungen erläutert wird, damit ich weiß, wie ich in Zukunft eine bessere Antwort schreiben kann 🙂
Ben Leggiero
4

Verwenden Sie NSURLComponents, um HTTP-GET-Parameter zu codieren:

    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/

Ralf Ebert
quelle
1
Es werden keine kaufmännischen Und-Zeichen, Schrägstriche oder Semikolons codiert.
Fábio Oliveira
4

Dieser Code hat mir beim Codieren von Sonderzeichen geholfen

NSString* encPassword = [password stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];
Rupesh Baldania
quelle
3

Schneller Code basierend auf der objc-Antwort von chown in diesem Thread.

extension String {
    func urlEncode() -> String {
        return CFURLCreateStringByAddingPercentEscapes(
            nil,
            self,
            nil,
            "!*'();:@&=+$,/?%#[]",
            CFStringBuiltInEncodings.UTF8.rawValue
        )
    }
}
neoneye
quelle
4
Diese Funktion war in iOS 9 veraltet :(
Oliver Atkinson
3

Probieren Sie in Swift 3 Folgendes aus:

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

Da stringByAddingPercentEscapesUsingEncodingnicht URL-Zeichen codiert werden, aber die reservierten Zeichen (wie !*'();:@&=+$,/?%#[]) verbleiben, können Sie die URL wie folgt codieren:

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

In schnellem 3:

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

// exclude hostname and symbols &,/ and etc
stringUrl = stringUrl.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!;
Meer-kg
quelle
2

In den Versionshinweisen zu 10.11 lautet der Rat von Apple:

Wenn Sie eine gesamte URL-Zeichenfolge prozentual codieren müssen, können Sie diesen Code verwenden, um einen NSString zu codieren, der als URL gedacht ist (in urlStringToEncode):

NSString *percentEncodedURLString =
  [[NSURL URLWithDataRepresentation:[urlStringToEncode dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil] relativeString];
Nithinbhaktha
quelle
scheint nicht zu funktionieren, Zeichen wie & werden immer noch alleine gelassen
kjyv
1

In meinem Fall, in dem die letzte Komponente arabische Buchstaben waren, habe ich Folgendes getan 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;
}
}

Verwendung:

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

if let encodedStringURL = stringURL.encodeUTF8() {

    if let url = NSURL(string: encodedStringURL) {

      ...
    }

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

laut folgendem blog

Anton Kashpor
quelle
Aber es ist in iOS 9 veraltet. Was ist der aktualisierte Code dafür?
Sujit Nachan
1

So viele Antworten, die aber bei mir nicht funktionierten, also habe ich Folgendes versucht:

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

Hoffentlich hilft es jemandem. Vielen Dank

Sanjeevcn
quelle
0

Für einzelne www-formularcodierte Abfrageparameter habe ich eine Kategorie für NSString erstellt:

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

// Dies ist ohne Test

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

Ich hatte ein ähnliches Problem beim Übergeben komplexer Zeichenfolgen als POST-Parameter. Meine Zeichenfolgen können asiatische Zeichen, Leerzeichen, Anführungszeichen und alle Arten von Sonderzeichen enthalten. Die Lösung, die ich schließlich fand, bestand darin, meine Zeichenfolge in die passende Reihe von Unicodes zu konvertieren, z. B. "Hu0040Hu0020Hu03f5 ....", wobei [NSString stringWithFormat: @ "Hu% 04x", [ZeichenfolgenzeichenAtIndex: i]] verwendet wurde, um den Unicode von jedem zu erhalten Zeichen in der ursprünglichen Zeichenfolge. Das gleiche kann in Java gemacht werden.

Diese Zeichenfolge kann sicher als POST-Parameter übergeben werden.

Auf der Serverseite (PHP) ändere ich das gesamte "H" in "\" und übergebe die resultierende Zeichenfolge an json_decode. Der letzte Schritt besteht darin, einfache Anführungszeichen zu umgehen, bevor die Zeichenfolge in MySQL gespeichert wird.

Auf diese Weise kann ich jede UTF8-Zeichenfolge auf meinem Server speichern.

Georges
quelle
0

Dieser arbeitet für mich.

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
}

Ich habe die obige Funktion über diesen Link gefunden: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/

Sie können diese Funktion auch mit schneller Erweiterung verwenden. Bitte lassen Sie mich wissen, wenn es ein Problem gibt.

Gaurav Singla
quelle