今天做域名加签校验遇到一个问题,就是请求地址编码问题,url地址如下:
NSString *tmpUrlString = @"https://www.baidu.com/devtest-news/app/news/keyword/recommend?keyword=土甲,巴利基斯,萨姆桑斯堡&test=你好*2";
,这里需要对参数里面的中文
和",","*"
等进行转义。
由于之前对NSCharacterSet
和stringByAddingPercentEncodingWithAllowedCharacters
方法没有细致了解,因此这里做了下笔记.
DEMO详见
一. NSCharacterSet
1.API解释
/** 001 根据一个给定的字符串获取一个NSCharacterSet对象 */
+ (NSCharacterSet *)characterSetWithCharactersInString:(NSString *)aString;
/** 002 相反字符串限制 【具体见接下的例子】 */
@property (readonly, copy) NSCharacterSet *invertedSet;
举个例子:
// 0 - 9字符集
NSString *numberStr = @"0123456789";
NSCharacterSet *numberSet = [NSCharacterSet characterSetWithCharactersInString:numberStr];
NSString *str = @"7chinafjf78990love";
// 过滤str字符串里面的0-9内的字符
NSLog(@"numberSet----%@",[[str componentsSeparatedByCharactersInSet:numberSet] componentsJoinedByString:@""]);
// 保留str字符串里面的0-9内的字符
NSCharacterSet *invertedSet = [[NSCharacterSet characterSetWithCharactersInString:numberStr] invertedSet];
NSLog(@"invertedSet----%@",[[str componentsSeparatedByCharactersInSet:invertedSet] componentsJoinedByString:@""]);
输出日志:
2021-01-02 16:08:02.239695+0800 FJFBlogDemo[13342:636161] numberSet----chinafjflove
2021-01-02 16:08:02.239784+0800 FJFBlogDemo[13342:636161] invertedSet----778990
2.常用快捷方法合集
[NSCharacterSet alphanumericCharacterSet]; //所有数字和字母(大小写)
[NSCharacterSet decimalDigitCharacterSet]; //0-9的数字
[NSCharacterSet letterCharacterSet]; //所有字母
[NSCharacterSet lowercaseLetterCharacterSet]; //小写字母
[NSCharacterSet uppercaseLetterCharacterSet]; //大写字母
[NSCharacterSet punctuationCharacterSet]; //标点符号
[NSCharacterSet whitespaceAndNewlineCharacterSet]; //空格和换行符
[NSCharacterSet whitespaceCharacterSet]; //空格
stringByAddingPercentEncodingWithAllowedCharacters方法
所以这两个函数可以解释如下:
// 对除了这些特殊字符(!$&'()*+-./:;=?@_~%#[])以外的所有字符进行编码
+ (NSString *)fjf_encodeSpecialCharacterWithUrlString:(NSString *)urlString {
return [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!$&'()*+-./:;=?@_~%#[]"]];
}
// 只编码 中文 字符(对所有字符都不进行编码,除了中文)
+ (NSString *)fjf_encodeChineseCharacterWithUrlString:(NSString *)urlString {
return [urlString stringByAddingPercentEncodingWithAllowedCharacters:[[NSCharacterSet characterSetWithCharactersInString:@""] invertedSet]];
}
对url统一处理方法
+ (NSString *)fjf_encodeUrlStringWithString:(NSString *)urlString {
//先截取问号
NSArray *allElements = [urlString componentsSeparatedByString:@"?"];
NSMutableDictionary *params = [NSMutableDictionary dictionary];//待set的参数字典
if (allElements.count == 2) {
//有参数或者?后面为空
NSString *myUrlString = allElements[0];
NSString *paramsString = allElements[1];
//获取参数对
NSArray *paramsArray = [paramsString componentsSeparatedByString:@"&"];
if (paramsArray.count >= 2) {
for (NSInteger i = 0; i < paramsArray.count; i++) {
NSString *singleParamString = paramsArray[i];
NSArray *singleParamSet = [singleParamString componentsSeparatedByString:@"="];
if (singleParamSet.count == 2) {
NSString *key = singleParamSet[0];
NSString *value = singleParamSet[1];
if (key.length > 0 || value.length > 0) {
[params setObject:[self fjf_percentEscapedStringWithString:value] forKey:[self fjf_percentEscapedStringWithString:key]];
}
}
}
} else if (paramsArray.count == 1) {
//无 &。url只有?后一个参数
NSString *singleParamString = paramsArray[0];
NSArray *singleParamSet = [singleParamString componentsSeparatedByString:@"="];
if (singleParamSet.count == 2) {
NSString *key = singleParamSet[0];
NSString *value = singleParamSet[1];
if (key.length || value.length) {
[params setObject:[self fjf_percentEscapedStringWithString:value] forKey:[self fjf_percentEscapedStringWithString:key]];
}
}
}
//整合url及参数
NSMutableString *tmpMstring = [NSMutableString stringWithString:myUrlString];
[params enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
[tmpMstring appendString:[self fjf_urlSymbolWithUrl:tmpMstring]];
[tmpMstring appendString:[NSString stringWithFormat:@"%@=%@", key, obj]];
}];
return tmpMstring;
}
return urlString;
}
+ (NSString *)fjf_percentEscapedStringWithString:(NSString *)string {
NSString * kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
NSString * kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
// FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028
// return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
static NSUInteger const batchSize = 50;
NSUInteger index = 0;
NSMutableString *escaped = @"".mutableCopy;
while (index < string.length) {
NSUInteger length = MIN(string.length - index, batchSize);
NSRange range = NSMakeRange(index, length);
// To avoid breaking up character sequences such as
range = [string rangeOfComposedCharacterSequencesForRange:range];
NSString *substring = [string substringWithRange:range];
NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
[escaped appendString:encoded];
index += range.length;
}
return escaped;
}
// 请求地址 拼接 符号
+ (NSString *)fjf_urlSymbolWithUrl:(NSString *)url {
NSString *symbolString = @"?";
if ([url containsString:@"?"]) {
symbolString = @"&";
}
return symbolString;
}