URL'yi bir dizeyi nasıl kodlarım


Yanıtlar:


291

Ne yazık ki, stringByAddingPercentEscapesUsingEncodingher zaman% 100 çalışmıyor. URL olmayan karakterleri kodlar, ancak ayrılmış karakterleri (eğik çizgi /ve "ve" işareti gibi &) tek başına bırakır . Görünüşe göre bu Apple'ın farkında olduğu bir hatadır , ancak henüz düzeltmedikleri için, bir dizeyi url kodlamak için bu kategoriyi kullanıyorum:

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

Bunun gibi kullanılır:

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

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

Bu da işe yarar:

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

Konu hakkında iyi okumalar:

Objective-c iPhone yüzde bir dize kodlar?
Objective-C ve Swift URL kodlaması

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
Neden her zaman hangi karakterlerden kaçmak istediğinizi açıkça belirtebileceğiniz CFURLCreateStringByAddingPercentEscapes'e () düşmek yerine neden böyle karmaşık bir kategori kullanasınız ?
Lily Ballard

8
@KevinBallard çünkü CF işlevi kapsayıcı bir model üzerinde çalışır ("bu karakterlerden kaç") ve genellikle özel bir model üzerinde çalışmak istersiniz (" bu karakterler dışında her şeyden
kaç


31
@DaveDeLong Anladığım yer bu olabilir. Tüm projelerimde bir yıl kadar standart bir kategori oldu, bu yüzden orijinal kaynak olabileceğini hayal ediyorum! Ben yazmak için kredi almaya çalışıyorum gibi görünmüyor yani ifadeler düzenledim).
chown

4
Neden? if (thisChar == '') {[çıktı appendString: @ "+"]; } Dışarıda beklediğim gibi% 20 ile boşlukları kodlayacaksa
Chris Stephens

127

Bu yardımcı olabilir

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

İOS 7+ için önerilen yol:

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

URL bileşeninin gereksinimine göre izin verilen karakter kümesini seçebilirsiniz.


7
Bu ayrıca '&', '?' Gibi parametre sınırlayıcıları doğru şekilde kodlamaz. içeriği bir API'ye geçirdiğiniz durumda.
Ben Lachman

'&', URL sorgu dizesi parametresi için geçerli bir karakter değil. Lütfen '& amp;' yerine.
Nishant

1
stringByAddingPercentEscapesUsingEncoding DEPRECATED " -stringByAddingPercentEncodingWithAllowedCharacters:Her zaman önerilen UTF-8 kodlamasını kullanan ve her bir URL bileşeni veya alt bileşeni geçerli karakterler için farklı kurallara sahip olduğundan belirli bir URL bileşeni veya alt bileşeni için kodlayan bunun yerine kullanın ."
Mihir Oza

89

Yanıt seçildiğinden beri yeni API'ler eklendi; Artık NSURLUtilities'i kullanabilirsiniz. URL'lerin farklı bölümleri farklı karakterlere izin verdiğinden, geçerli karakter kümesini kullanın. Aşağıdaki örnek, sorgu dizesine dahil edilmek üzere kodlar:

encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];

'&' Kelimesini özel olarak dönüştürmek için URL sorgusunda URL sorgusu kümesinden kaldırmanız veya farklı bir küme kullanmanız gerekir.

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

1
"NSURLUtilities'i kullan" ile ne demek istediğini anlamanız biraz zaman aldı - ama şimdi Apple'ın bu yeni yöntemi iOS 7 ve OS X 10.9'da tanımladığı NSString kategorisinin adı olduğunu görüyorum.
Richard Venable

1
Burada bunun gibi daha ayrıntılı bir cevap var: stackoverflow.com/a/20271177/456366
Richard Venable

Evet. Ayrıca, piyasaya sürülen yeni API'ların listesinde NSURLUtilities olarak da listelenmiştir.
Peter DeWeese

'&' tabiki bir sorgu dizesinde kullanılabilir, bu yüzden Richard'ın bağlantısını kullanarak cevabımı düzenleyeceğim.
Peter DeWeese

3
NSMakeRange('&', 1)Swift'te çalışmaz, çünkü Swift, charların korsan olmadan int dönüşümüne izin vermez. Bu çözümü Swift kodunda kullanmak için removeCharactersInString("&"),.removeCharactersInRange(...)
cbh2000 6:15

16

Swift 2.0 Örneği (iOS 9 Uyumlu)

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
Buraya ulaşmak için birkaç çembere atlamak zorundasınız gibi görünüyor, bu yüzden onu bir uzantıda gizlemek daha iyi
Oliver Atkinson

@OliverAtkinson - benim için Int (String (Character ("&"))) gerektiği gibi nil döndürür. Bunun yerine characters.removeCharactersInString ("&").
ambientlight

14

ios 7 güncellemesi

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

NSString *decode = [encode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

Bu yanlış. URL'nin farklı bölümlerinden farklı şekilde kaçmak isteyeceksiniz. stackoverflow.com/questions/3423545/…
Steve Moser

Aslında, izin verilen karakterler için sunucunuza bağlıdır, burada benim sunucuda sadece alfanümerik karakter kümesine izin verdiğimi kullanıyordum, ihtiyaçlarınızı karşılamak için belirli karakterlerle değiştirebilirsiniz.
Underdog

1
Soru '&' karakterini kodlamayı soruyor.
Steve Moser

8

CFURLCreateStringByAddingPercentEscapesAramayı kabul edilen cevapla verilen şekilde kullanmayı tercih ettim , ancak XCode'un (ve IOS) en yeni sürümünde, bir hatayla sonuçlandı, bu nedenle aşağıdaki kullanılır:

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

Alanı kodlamıyor. Örnek @ "string string" ve @ "string & string" düzgün bir şekilde kodlanmıştır. Lütfen girişinizi bana bildirin.
Yogesh Lolusare

2
Benim için çoğu zaman bunu çözmek için harcanan inkar dönemi, çerçevenin etrafta karışıklık olmadan bunu yapan 'urlencode' adlı bir şey içermediğine inanmayı reddettiğim inkar dönemi oldu ..
dancl

6

stringByAddingPercentEncodingWithAllowedCharactersYöntemi kullanmaya çalışın [NSCharacterSet URLUserAllowedCharacterSet]tüm vakaları kapsayacak

Hedef C

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

hızlı

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

Çıktı

Test%20%2F%20Test


6

Bu konuyla ilgili tüm cevapları ve ( yanlış ) kabul edileni okuduktan sonra katkımı eklemek istiyorum.

EĞER hedef iOS7 + olduğu ve 2017 yılında bu XCode hızlı, iOS8, en iyi şekilde, iplik kasa altında uyumluluğu sağlamak için gerçekten zor kılan gerektiğinden, amd tam UTF-8 desteği Bunu yapmanın olacaktır:

(Amaç C kodu)

@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

Bu, NSString'i genişletir, RFC yasak karakterlerini hariç tutar, UTF-8 karakterlerini destekler ve aşağıdaki gibi şeyleri kullanmanıza izin verir:

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

Hata ayıklama konsolunuza yazdırılacaktır:

Kaynak: Ben [şeytan] ve kırmak istiyorum !!! % A0% C3% A9% C3% AC% C3% B2% C3% B9

... ayrıca çok iş parçacıklı ortamlarda birden çok başlatmayı önlemek için dispatch_once kullanımını unutmayın.


5

İşte Swift 5.x'te üretime hazır esnek bir yaklaşım :

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

Örnek kullanım:

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

Çıktı:

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

Lütfen aşağı oylarınızın nedenini açıklayan bir yorum ekleyin, böylece gelecekte daha iyi bir cevap yazmayı biliyorum
Ben

4

HTTP GET parametrelerini kodlamak için NSURLComponents kullanın:

    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
Ve işaretleri, eğik çizgiler veya noktalı virgülleri kodlamaz.
Fábio Oliveira

4

Bu kod özel karakterleri kodlamama yardımcı oldu

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

3

Bu konudaki chown cevabı cevabını temel alan swift kodu .

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

4
bu işlev iOS 9'da kaldırıldı :(
Oliver Atkinson

3

In Swift 3 , aşağıda deneyin:

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

stringByAddingPercentEscapesUsingEncodingURL olmayan karakterleri kodladığı , ancak ayrılmış karakterleri bıraktığı (gibi !*'();:@&=+$,/?%#[]), URL'yi aşağıdaki kod gibi kodlayabilirsiniz:

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

2

Hızlı 3'te:

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

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

2

Apple'ın 10.11 sürüm notlarındaki tavsiyesi:

Bir URL dizesinin tamamını yüzde olarak kodlamanız gerekiyorsa, URL olması amaçlanan bir NSString kodlamasını (urlStringToEncode içinde) kodlamak için bu kodu kullanabilirsiniz:

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

çalışmıyor gibi görünüyor ve hala yalnız kaldı
kjyv

1

Son bileşenin Arap harfleri olduğu durumumda aşağıdakileri yaptım 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;
}
}

kullanımı:

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

göre aşağıdaki blogda


Ancak iOS 9'da kullanımdan kaldırıldı. Bunun güncellenmiş kodu nedir?
Sujit Nachan

1

Çok fazla cevap ama benim için çalışmadı, bu yüzden aşağıdakileri denedim:

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

Umarım birine yardım eder. Teşekkürler


0

Bireysel www form kodlu sorgu parametreleri için NSString üzerinde bir kategori yaptım:

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

0

// Bu testsiz

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

0

POST parametresi olarak karmaşık dizeleri geçen benzer bir sorunla karşılaştım. Dizelerim Asya karakterleri, boşluklar, tırnak işaretleri ve her türlü özel karakter içerebilir. Sonunda bulduğum çözüm, her biri Unicode'u almak için [NSString stringWithFormat: @ "Hu% 04x", [string characterAtIndex: i]] kullanarak dizimi eşleşen unicodes serisine dönüştürmekti, örneğin "Hu0040Hu0020Hu03f5 ...." karakter. Aynı şey Java için de yapılabilir.

Bu dize bir POST parametresi olarak güvenli bir şekilde geçirilebilir.

Sunucu tarafında (PHP), tüm "H" "\" değiştirmek ve ortaya çıkan dize json_decode için geçirin. Son adım, dizeyi MySQL'e kaydetmeden önce tek tırnaklardan kaçmaktır.

Bu şekilde herhangi bir UTF8 dizesini sunucumda saklayabilirim.


0

Bu benim için çalışıyor.

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
}

Yukarıdaki işlevi bu bağlantıdan buldum: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/

Bu işlevi hızlı uzantı ile de kullanabilirsiniz. Herhangi bir sorun olursa lütfen bize bildirin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.