New file |
| | |
| | | // |
| | | // NSString+YYAdd.m |
| | | // YYCategories <https://github.com/ibireme/YYCategories> |
| | | // |
| | | // Created by ibireme on 13/4/3. |
| | | // Copyright (c) 2015 ibireme. |
| | | // |
| | | // This source code is licensed under the MIT-style license found in the |
| | | // LICENSE file in the root directory of this source tree. |
| | | // |
| | | |
| | | #import "NSString+YYAdd.h" |
| | | #import "NSData+YYAdd.h" |
| | | #import "NSNumber+YYAdd.h" |
| | | #import "UIDevice+YYAdd.h" |
| | | #import "YYCategoriesMacro.h" |
| | | |
| | | YYSYNTH_DUMMY_CLASS(NSString_YYAdd) |
| | | |
| | | |
| | | @implementation NSString (YYAdd) |
| | | |
| | | - (NSString *)md2String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] md2String]; |
| | | } |
| | | |
| | | - (NSString *)md4String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] md4String]; |
| | | } |
| | | |
| | | - (NSString *)md5String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] md5String]; |
| | | } |
| | | |
| | | - (NSString *)sha1String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] sha1String]; |
| | | } |
| | | |
| | | - (NSString *)sha224String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] sha224String]; |
| | | } |
| | | |
| | | - (NSString *)sha256String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] sha256String]; |
| | | } |
| | | |
| | | - (NSString *)sha384String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] sha384String]; |
| | | } |
| | | |
| | | - (NSString *)sha512String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] sha512String]; |
| | | } |
| | | |
| | | - (NSString *)crc32String { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] crc32String]; |
| | | } |
| | | |
| | | - (NSString *)hmacMD5StringWithKey:(NSString *)key { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] |
| | | hmacMD5StringWithKey:key]; |
| | | } |
| | | |
| | | - (NSString *)hmacSHA1StringWithKey:(NSString *)key { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] |
| | | hmacSHA1StringWithKey:key]; |
| | | } |
| | | |
| | | - (NSString *)hmacSHA224StringWithKey:(NSString *)key { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] |
| | | hmacSHA224StringWithKey:key]; |
| | | } |
| | | |
| | | - (NSString *)hmacSHA256StringWithKey:(NSString *)key { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] |
| | | hmacSHA256StringWithKey:key]; |
| | | } |
| | | |
| | | - (NSString *)hmacSHA384StringWithKey:(NSString *)key { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] |
| | | hmacSHA384StringWithKey:key]; |
| | | } |
| | | |
| | | - (NSString *)hmacSHA512StringWithKey:(NSString *)key { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] |
| | | hmacSHA512StringWithKey:key]; |
| | | } |
| | | |
| | | - (NSString *)base64EncodedString { |
| | | return [[self dataUsingEncoding:NSUTF8StringEncoding] base64EncodedString]; |
| | | } |
| | | |
| | | + (NSString *)stringWithBase64EncodedString:(NSString *)base64EncodedString { |
| | | NSData *data = [NSData dataWithBase64EncodedString:base64EncodedString]; |
| | | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; |
| | | } |
| | | |
| | | - (NSString *)stringByURLEncode { |
| | | if ([self respondsToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)]) { |
| | | /** |
| | | AFNetworking/AFURLRequestSerialization.m |
| | | |
| | | Returns a percent-escaped string following RFC 3986 for a query string key or value. |
| | | RFC 3986 states that the following characters are "reserved" characters. |
| | | - General Delimiters: ":", "#", "[", "]", "@", "?", "/" |
| | | - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=" |
| | | In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow |
| | | query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/" |
| | | should be percent-escaped in the query string. |
| | | - parameter string: The string to be percent-escaped. |
| | | - returns: The percent-escaped string. |
| | | */ |
| | | static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4 |
| | | static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;="; |
| | | |
| | | NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; |
| | | [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]]; |
| | | static NSUInteger const batchSize = 50; |
| | | |
| | | NSUInteger index = 0; |
| | | NSMutableString *escaped = @"".mutableCopy; |
| | | |
| | | while (index < self.length) { |
| | | NSUInteger length = MIN(self.length - index, batchSize); |
| | | NSRange range = NSMakeRange(index, length); |
| | | // To avoid breaking up character sequences such as 👴🏻👮🏽 |
| | | range = [self rangeOfComposedCharacterSequencesForRange:range]; |
| | | NSString *substring = [self substringWithRange:range]; |
| | | NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; |
| | | [escaped appendString:encoded]; |
| | | |
| | | index += range.length; |
| | | } |
| | | return escaped; |
| | | } else { |
| | | #pragma clang diagnostic push |
| | | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| | | CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding); |
| | | NSString *encoded = (__bridge_transfer NSString *) |
| | | CFURLCreateStringByAddingPercentEscapes( |
| | | kCFAllocatorDefault, |
| | | (__bridge CFStringRef)self, |
| | | NULL, |
| | | CFSTR("!#$&'()*+,/:;=?@[]"), |
| | | cfEncoding); |
| | | return encoded; |
| | | #pragma clang diagnostic pop |
| | | } |
| | | } |
| | | |
| | | - (NSString *)stringByURLDecode { |
| | | if ([self respondsToSelector:@selector(stringByRemovingPercentEncoding)]) { |
| | | return [self stringByRemovingPercentEncoding]; |
| | | } else { |
| | | #pragma clang diagnostic push |
| | | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| | | CFStringEncoding en = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding); |
| | | NSString *decoded = [self stringByReplacingOccurrencesOfString:@"+" |
| | | withString:@" "]; |
| | | decoded = (__bridge_transfer NSString *) |
| | | CFURLCreateStringByReplacingPercentEscapesUsingEncoding( |
| | | NULL, |
| | | (__bridge CFStringRef)decoded, |
| | | CFSTR(""), |
| | | en); |
| | | return decoded; |
| | | #pragma clang diagnostic pop |
| | | } |
| | | } |
| | | |
| | | - (NSString *)stringByEscapingHTML { |
| | | NSUInteger len = self.length; |
| | | if (!len) return self; |
| | | |
| | | unichar *buf = malloc(sizeof(unichar) * len); |
| | | if (!buf) return self; |
| | | [self getCharacters:buf range:NSMakeRange(0, len)]; |
| | | |
| | | NSMutableString *result = [NSMutableString string]; |
| | | for (int i = 0; i < len; i++) { |
| | | unichar c = buf[i]; |
| | | NSString *esc = nil; |
| | | switch (c) { |
| | | case 34: esc = @"""; break; |
| | | case 38: esc = @"&"; break; |
| | | case 39: esc = @"'"; break; |
| | | case 60: esc = @"<"; break; |
| | | case 62: esc = @">"; break; |
| | | default: break; |
| | | } |
| | | if (esc) { |
| | | [result appendString:esc]; |
| | | } else { |
| | | CFStringAppendCharacters((CFMutableStringRef)result, &c, 1); |
| | | } |
| | | } |
| | | free(buf); |
| | | return result; |
| | | } |
| | | |
| | | - (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode { |
| | | CGSize result; |
| | | if (!font) font = [UIFont systemFontOfSize:12]; |
| | | if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) { |
| | | NSMutableDictionary *attr = [NSMutableDictionary new]; |
| | | attr[NSFontAttributeName] = font; |
| | | if (lineBreakMode != NSLineBreakByWordWrapping) { |
| | | NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new]; |
| | | paragraphStyle.lineBreakMode = lineBreakMode; |
| | | attr[NSParagraphStyleAttributeName] = paragraphStyle; |
| | | } |
| | | CGRect rect = [self boundingRectWithSize:size |
| | | options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading |
| | | attributes:attr context:nil]; |
| | | result = rect.size; |
| | | } else { |
| | | #pragma clang diagnostic push |
| | | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| | | result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode]; |
| | | #pragma clang diagnostic pop |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | - (CGFloat)widthForFont:(UIFont *)font { |
| | | CGSize size = [self sizeForFont:font size:CGSizeMake(HUGE, HUGE) mode:NSLineBreakByWordWrapping]; |
| | | return size.width; |
| | | } |
| | | |
| | | - (CGFloat)heightForFont:(UIFont *)font width:(CGFloat)width { |
| | | CGSize size = [self sizeForFont:font size:CGSizeMake(width, HUGE) mode:NSLineBreakByWordWrapping]; |
| | | return size.height; |
| | | } |
| | | |
| | | - (BOOL)matchesRegex:(NSString *)regex options:(NSRegularExpressionOptions)options { |
| | | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:NULL]; |
| | | if (!pattern) return NO; |
| | | return ([pattern numberOfMatchesInString:self options:0 range:NSMakeRange(0, self.length)] > 0); |
| | | } |
| | | |
| | | - (void)enumerateRegexMatches:(NSString *)regex |
| | | options:(NSRegularExpressionOptions)options |
| | | usingBlock:(void (^)(NSString *match, NSRange matchRange, BOOL *stop))block { |
| | | if (regex.length == 0 || !block) return; |
| | | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil]; |
| | | if (!regex) return; |
| | | [pattern enumerateMatchesInString:self options:kNilOptions range:NSMakeRange(0, self.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { |
| | | block([self substringWithRange:result.range], result.range, stop); |
| | | }]; |
| | | } |
| | | |
| | | - (NSString *)stringByReplacingRegex:(NSString *)regex |
| | | options:(NSRegularExpressionOptions)options |
| | | withString:(NSString *)replacement; { |
| | | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil]; |
| | | if (!pattern) return self; |
| | | return [pattern stringByReplacingMatchesInString:self options:0 range:NSMakeRange(0, [self length]) withTemplate:replacement]; |
| | | } |
| | | |
| | | - (char)charValue { |
| | | return self.numberValue.charValue; |
| | | } |
| | | |
| | | - (unsigned char) unsignedCharValue { |
| | | return self.numberValue.unsignedCharValue; |
| | | } |
| | | |
| | | - (short) shortValue { |
| | | return self.numberValue.shortValue; |
| | | } |
| | | |
| | | - (unsigned short) unsignedShortValue { |
| | | return self.numberValue.unsignedShortValue; |
| | | } |
| | | |
| | | - (unsigned int) unsignedIntValue { |
| | | return self.numberValue.unsignedIntValue; |
| | | } |
| | | |
| | | - (long) longValue { |
| | | return self.numberValue.longValue; |
| | | } |
| | | |
| | | - (unsigned long) unsignedLongValue { |
| | | return self.numberValue.unsignedLongValue; |
| | | } |
| | | |
| | | - (unsigned long long) unsignedLongLongValue { |
| | | return self.numberValue.unsignedLongLongValue; |
| | | } |
| | | |
| | | - (NSUInteger) unsignedIntegerValue { |
| | | return self.numberValue.unsignedIntegerValue; |
| | | } |
| | | |
| | | |
| | | + (NSString *)stringWithUUID { |
| | | CFUUIDRef uuid = CFUUIDCreate(NULL); |
| | | CFStringRef string = CFUUIDCreateString(NULL, uuid); |
| | | CFRelease(uuid); |
| | | return (__bridge_transfer NSString *)string; |
| | | } |
| | | |
| | | + (NSString *)stringWithUTF32Char:(UTF32Char)char32 { |
| | | char32 = NSSwapHostIntToLittle(char32); |
| | | return [[NSString alloc] initWithBytes:&char32 length:4 encoding:NSUTF32LittleEndianStringEncoding]; |
| | | } |
| | | |
| | | + (NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length { |
| | | return [[NSString alloc] initWithBytes:(const void *)char32 |
| | | length:length * 4 |
| | | encoding:NSUTF32LittleEndianStringEncoding]; |
| | | } |
| | | |
| | | - (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block { |
| | | NSString *str = self; |
| | | if (range.location != 0 || range.length != self.length) { |
| | | str = [self substringWithRange:range]; |
| | | } |
| | | NSUInteger len = [str lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4; |
| | | UTF32Char *char32 = (UTF32Char *)[str cStringUsingEncoding:NSUTF32LittleEndianStringEncoding]; |
| | | if (len == 0 || char32 == NULL) return; |
| | | |
| | | NSUInteger location = 0; |
| | | BOOL stop = NO; |
| | | NSRange subRange; |
| | | UTF32Char oneChar; |
| | | |
| | | for (NSUInteger i = 0; i < len; i++) { |
| | | oneChar = char32[i]; |
| | | subRange = NSMakeRange(location, oneChar > 0xFFFF ? 2 : 1); |
| | | block(oneChar, subRange, &stop); |
| | | if (stop) return; |
| | | location += subRange.length; |
| | | } |
| | | } |
| | | |
| | | - (NSString *)stringByTrim { |
| | | NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet]; |
| | | return [self stringByTrimmingCharactersInSet:set]; |
| | | } |
| | | |
| | | - (NSString *)stringByAppendingNameScale:(CGFloat)scale { |
| | | if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy; |
| | | return [self stringByAppendingFormat:@"@%@x", @(scale)]; |
| | | } |
| | | |
| | | - (NSString *)stringByAppendingPathScale:(CGFloat)scale { |
| | | if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy; |
| | | NSString *ext = self.pathExtension; |
| | | NSRange extRange = NSMakeRange(self.length - ext.length, 0); |
| | | if (ext.length > 0) extRange.location -= 1; |
| | | NSString *scaleStr = [NSString stringWithFormat:@"@%@x", @(scale)]; |
| | | return [self stringByReplacingCharactersInRange:extRange withString:scaleStr]; |
| | | } |
| | | |
| | | - (CGFloat)pathScale { |
| | | if (self.length == 0 || [self hasSuffix:@"/"]) return 1; |
| | | NSString *name = self.stringByDeletingPathExtension; |
| | | __block CGFloat scale = 1; |
| | | [name enumerateRegexMatches:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines usingBlock: ^(NSString *match, NSRange matchRange, BOOL *stop) { |
| | | scale = [match substringWithRange:NSMakeRange(1, match.length - 2)].doubleValue; |
| | | }]; |
| | | return scale; |
| | | } |
| | | |
| | | - (BOOL)isNotBlank { |
| | | NSCharacterSet *blank = [NSCharacterSet whitespaceAndNewlineCharacterSet]; |
| | | for (NSInteger i = 0; i < self.length; ++i) { |
| | | unichar c = [self characterAtIndex:i]; |
| | | if (![blank characterIsMember:c]) { |
| | | return YES; |
| | | } |
| | | } |
| | | return NO; |
| | | } |
| | | |
| | | - (BOOL)containsString:(NSString *)string { |
| | | if (string == nil) return NO; |
| | | return [self rangeOfString:string].location != NSNotFound; |
| | | } |
| | | |
| | | - (BOOL)containsCharacterSet:(NSCharacterSet *)set { |
| | | if (set == nil) return NO; |
| | | return [self rangeOfCharacterFromSet:set].location != NSNotFound; |
| | | } |
| | | |
| | | - (NSNumber *)numberValue { |
| | | return [NSNumber numberWithString:self]; |
| | | } |
| | | |
| | | - (NSData *)dataValue { |
| | | return [self dataUsingEncoding:NSUTF8StringEncoding]; |
| | | } |
| | | |
| | | - (NSRange)rangeOfAll { |
| | | return NSMakeRange(0, self.length); |
| | | } |
| | | |
| | | - (id)jsonValueDecoded { |
| | | return [[self dataValue] jsonValueDecoded]; |
| | | } |
| | | |
| | | + (NSString *)stringNamed:(NSString *)name { |
| | | NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@""]; |
| | | NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL]; |
| | | if (!str) { |
| | | path = [[NSBundle mainBundle] pathForResource:name ofType:@"txt"]; |
| | | str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL]; |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | @end |