Кодировка URL Objective-C и Swift
У меня есть NSString
как это:
http://www.
но я хочу преобразовать его в:
http%3A%2F%2Fwww.
Как я могу это сделать?
13 ответов
Чтобы избежать персонажей, которых вы хотите, это немного больше работы.
Пример кода
iOS7 и выше:
NSString *unescaped = @"http://www";
NSString *escapedString = [unescaped stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
NSLog(@"escapedString: %@", escapedString);
NSLog вывод:
escapedString: http% 3A% 2F% 2Fwww
Ниже приведены полезные наборы символов кодировки URL:
URLFragmentAllowedCharacterSet "#%<>[\]^`{|}
URLHostAllowedCharacterSet "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|}
URLUserAllowedCharacterSet "#%/:<>?@[\]^`
Создание набора символов, объединяющего все вышеперечисленное:
NSCharacterSet *URLCombinedCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@" \"#%/:<>?@[\\]^`{|}"] invertedSet];
Создание Base64
В случае набора символов Base64:
NSCharacterSet *URLBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"/+=\n"] invertedSet];
Для Swift 3.0:
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters:.urlHostAllowed)
Для Swift 2.x:
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
Замечания: stringByAddingPercentEncodingWithAllowedCharacters
также будет кодировать символы UTF-8, нуждающиеся в кодировании.
Предварительно iOS7 использовать Core Foundation
Использование Core Foundation с ARC:
NSString *escapedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
NULL,
(__bridge CFStringRef) unescaped,
NULL,
CFSTR("!*'();:@&=+$,/?%#[]\" "),
kCFStringEncodingUTF8));
Использование Core Foundation без ARC:
NSString *escapedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unescaped,
NULL,
CFSTR("!*'();:@&=+$,/?%#[]\" "),
kCFStringEncodingUTF8);
Замечания: -stringByAddingPercentEscapesUsingEncoding
не будет производить правильную кодировку, в этом случае он не будет кодировать что-либо, возвращающее ту же строку.
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding
кодирует 14 символов:
`#% ^ {} [] | \"<> плюс символ пробела в процентах.
СравниваемаяСтрока:
" `~!@#$%^&*()_+-={}[]|\\:;\"'<,>.?/AZaz"
encodedString:
"%20%60~!@%23$%25%5E&*()_+-=%7B%7D%5B%5D%7C%5C:;%22'%3C,%3E.?/AZaz"
Примечание: подумайте, соответствует ли этот набор символов вашим потребностям, если не измените их по мере необходимости.
RFC 3986 символов, требующих кодирования (добавлено%, поскольку это символ префикса кодирования):
"#$&'()*+,/:;!? = @[]%"
Некоторые "незарезервированные символы" дополнительно кодируются:
"\ n \ r \"% -.<> \ ^ _ `{|} ~"
Это называется кодированием URL. Больше здесь.
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)self,
NULL,
(CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
CFStringConvertNSStringEncodingToEncoding(encoding));
}
Это не мое решение. Кто-то еще написал в stackru, но я забыл, как.
Как-то это решение работает "хорошо". Он обрабатывает диакритические знаки, китайские иероглифы и многое другое.
- (NSString *) URLEncodedString {
NSMutableString * output = [NSMutableString string];
const char * source = [self UTF8String];
int sourceLen = strlen(source);
for (int i = 0; i < sourceLen; ++i) {
const unsigned char thisChar = (const unsigned char)source[i];
if (false && 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;
}
Если кто-то скажет мне, кто написал этот код, я очень ценю это. В основном у него есть объяснение, почему эта закодированная строка будет декодироваться именно так, как она хочет.
Я немного изменил его решение. Мне нравится, когда пространство обозначается символом%20, а не +. Это все.
NSString * encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NUL,(CFStringRef)@"parameter",NULL,(CFStringRef)@"!*'();@&+$,/?%#[]~=_-.:",kCFStringEncodingUTF8 );
NSURL * url = [[NSURL alloc] initWithString:[@"address here" stringByAppendingFormat:@"?cid=%@",encodedString, nil]];
Это может работать в Objective C ARC. Используйте CFBridgingRelease для приведения базового объекта в стиле Foundation в качестве объекта Objective C и передачи владения этим объектом в ARC. См. Функцию CFBridgingRelease здесь.
+ (NSString *)encodeUrlString:(NSString *)string {
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes
(kCFAllocatorDefault,
(__bridge CFStringRef)string,
NULL,
CFSTR("!*'();:@&=+$,/?%#[]"),
kCFStringEncodingUTF8)
);}
Вот что я использую. Обратите внимание, что вы должны использовать @autoreleasepool
функция или программа может привести к сбою или блокировке IDE. Мне пришлось три раза перезапускать свою IDE, пока я не понял, что исправить. Похоже, этот код соответствует ARC.
Этот вопрос задавался много раз, и было дано много ответов, но, к сожалению, все выбранные (и несколько других предложенных) неверны.
Вот тестовая строка, которую я использовал: This is my 123+ test & test2. Got it?!
Это мои методы класса Objective C++:
static NSString * urlDecode(NSString *stringToDecode) {
NSString *result = [stringToDecode stringByReplacingOccurrencesOfString:@"+" withString:@" "];
result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return result;
}
static NSString * urlEncode(NSString *stringToEncode) {
@autoreleasepool {
NSString *result = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)stringToEncode,
NULL,
(CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
kCFStringEncodingUTF8
));
result = [result stringByReplacingOccurrencesOfString:@"%20" withString:@"+"];
return result;
}
}
Swift iOS:
Просто для информации: я использовал это:
extension String {
func urlEncode() -> CFString {
return CFURLCreateStringByAddingPercentEscapes(
nil,
self,
nil,
"!*'();:@&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)
}
}// end extension String
NSString *str = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)yourString,
NULL,
CFSTR("/:"),
kCFStringEncodingUTF8);
Вам нужно будет выпустить или авто-релиз str
сам.
Google реализует это в своем Google Toolbox для Mac. Так что это хорошее место, чтобы показать, как они это делают. Другой вариант - включить Toolbox и использовать их реализацию.
Оформить заказ здесь. (Который сводится к тому, что люди публикуют здесь).
Вот что я сделал на Swift 5:
func formatPassword() -> String {
var output = "";
for ch in self {
let char = String(ch)
switch ch {
case " ":
output.append("+")
break
case ".", "-", "_", "~", "a"..."z", "A"..."Z", "0"..."9":
output.append(char)
break
default:
print(ch)
let unicode = char.unicodeScalars.first?.value ?? 0
let unicodeValue = NSNumber(value: unicode).intValue
let hexValue = String(format: "%02X", arguments: [unicodeValue])
output = output.appendingFormat("%%%@", hexValue)
}
}
return output as String
}
Затем я вызвал эту функцию, где я определил свой пароль.
Вот как я делаю это по-быстрому.
extension String {
func encodeURIComponent() -> String {
return self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
}
func decodeURIComponent() -> String {
return self.componentsSeparatedByString("+").joinWithSeparator(" ").stringByRemovingPercentEncoding!
}
}
// использовать метод экземпляра NSString следующим образом:
+ (NSString *)encodeURIComponent:(NSString *)string
{
NSString *s = [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return s;
}
+ (NSString *)decodeURIComponent:(NSString *)string
{
NSString *s = [string stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return s;
}
помните, вы должны кодировать или декодировать только значение вашего параметра, а не все URL, которые вы запрашиваете.
int strLength = 0;
NSString *urlStr = @"http://www";
NSLog(@" urlStr : %@", urlStr );
NSMutableString *mutableUrlStr = [urlStr mutableCopy];
NSLog(@" mutableUrlStr : %@", mutableUrlStr );
strLength = [mutableUrlStr length];
[mutableUrlStr replaceOccurrencesOfString:@":" withString:@"%3A" options:NSCaseInsensitiveSearch range:NSMakeRange(0, strLength)];
NSLog(@" mutableUrlStr : %@", mutableUrlStr );
strLength = [mutableUrlStr length];
[mutableUrlStr replaceOccurrencesOfString:@"/" withString:@"%2F" options:NSCaseInsensitiveSearch range:NSMakeRange(0, strLength)];
NSLog(@" mutableUrlStr : %@", mutableUrlStr );