NSString+YYAdd.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. //
  2. // NSString+YYAdd.m
  3. // YYKit <https://github.com/ibireme/YYKit>
  4. //
  5. // Created by ibireme on 13/4/3.
  6. // Copyright (c) 2015 ibireme.
  7. //
  8. // This source code is licensed under the MIT-style license found in the
  9. // LICENSE file in the root directory of this source tree.
  10. //
  11. #import "NSString+YYAdd.h"
  12. #import "NSData+YYAdd.h"
  13. #import "NSNumber+YYAdd.h"
  14. #import "UIDevice+YYAdd.h"
  15. #import "YYKitMacro.h"
  16. YYSYNTH_DUMMY_CLASS(NSString_YYAdd)
  17. @implementation NSString (YYAdd)
  18. - (NSString *)md2String {
  19. return [[self dataUsingEncoding:NSUTF8StringEncoding] md2String];
  20. }
  21. - (NSString *)md4String {
  22. return [[self dataUsingEncoding:NSUTF8StringEncoding] md4String];
  23. }
  24. - (NSString *)md5String {
  25. return [[self dataUsingEncoding:NSUTF8StringEncoding] md5String];
  26. }
  27. - (NSString *)sha1String {
  28. return [[self dataUsingEncoding:NSUTF8StringEncoding] sha1String];
  29. }
  30. - (NSString *)sha224String {
  31. return [[self dataUsingEncoding:NSUTF8StringEncoding] sha224String];
  32. }
  33. - (NSString *)sha256String {
  34. return [[self dataUsingEncoding:NSUTF8StringEncoding] sha256String];
  35. }
  36. - (NSString *)sha384String {
  37. return [[self dataUsingEncoding:NSUTF8StringEncoding] sha384String];
  38. }
  39. - (NSString *)sha512String {
  40. return [[self dataUsingEncoding:NSUTF8StringEncoding] sha512String];
  41. }
  42. - (NSString *)crc32String {
  43. return [[self dataUsingEncoding:NSUTF8StringEncoding] crc32String];
  44. }
  45. - (NSString *)hmacMD5StringWithKey:(NSString *)key {
  46. return [[self dataUsingEncoding:NSUTF8StringEncoding]
  47. hmacMD5StringWithKey:key];
  48. }
  49. - (NSString *)hmacSHA1StringWithKey:(NSString *)key {
  50. return [[self dataUsingEncoding:NSUTF8StringEncoding]
  51. hmacSHA1StringWithKey:key];
  52. }
  53. - (NSString *)hmacSHA224StringWithKey:(NSString *)key {
  54. return [[self dataUsingEncoding:NSUTF8StringEncoding]
  55. hmacSHA224StringWithKey:key];
  56. }
  57. - (NSString *)hmacSHA256StringWithKey:(NSString *)key {
  58. return [[self dataUsingEncoding:NSUTF8StringEncoding]
  59. hmacSHA256StringWithKey:key];
  60. }
  61. - (NSString *)hmacSHA384StringWithKey:(NSString *)key {
  62. return [[self dataUsingEncoding:NSUTF8StringEncoding]
  63. hmacSHA384StringWithKey:key];
  64. }
  65. - (NSString *)hmacSHA512StringWithKey:(NSString *)key {
  66. return [[self dataUsingEncoding:NSUTF8StringEncoding]
  67. hmacSHA512StringWithKey:key];
  68. }
  69. - (NSString *)base64EncodedString {
  70. return [[self dataUsingEncoding:NSUTF8StringEncoding] base64EncodedString];
  71. }
  72. + (NSString *)stringWithBase64EncodedString:(NSString *)base64EncodedString {
  73. NSData *data = [NSData dataWithBase64EncodedString:base64EncodedString];
  74. return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  75. }
  76. - (NSString *)stringByURLEncode {
  77. if ([self respondsToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)]) {
  78. /**
  79. AFNetworking/AFURLRequestSerialization.m
  80. Returns a percent-escaped string following RFC 3986 for a query string key or value.
  81. RFC 3986 states that the following characters are "reserved" characters.
  82. - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
  83. - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
  84. In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
  85. query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
  86. should be percent-escaped in the query string.
  87. - parameter string: The string to be percent-escaped.
  88. - returns: The percent-escaped string.
  89. */
  90. static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
  91. static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
  92. NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
  93. [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
  94. static NSUInteger const batchSize = 50;
  95. NSUInteger index = 0;
  96. NSMutableString *escaped = @"".mutableCopy;
  97. while (index < self.length) {
  98. NSUInteger length = MIN(self.length - index, batchSize);
  99. NSRange range = NSMakeRange(index, length);
  100. // To avoid breaking up character sequences such as 👴🏻👮🏽
  101. range = [self rangeOfComposedCharacterSequencesForRange:range];
  102. NSString *substring = [self substringWithRange:range];
  103. NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
  104. [escaped appendString:encoded];
  105. index += range.length;
  106. }
  107. return escaped;
  108. } else {
  109. #pragma clang diagnostic push
  110. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  111. CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding);
  112. NSString *encoded = (__bridge_transfer NSString *)
  113. CFURLCreateStringByAddingPercentEscapes(
  114. kCFAllocatorDefault,
  115. (__bridge CFStringRef)self,
  116. NULL,
  117. CFSTR("!#$&'()*+,/:;=?@[]"),
  118. cfEncoding);
  119. return encoded;
  120. #pragma clang diagnostic pop
  121. }
  122. }
  123. - (NSString *)stringByURLDecode {
  124. if ([self respondsToSelector:@selector(stringByRemovingPercentEncoding)]) {
  125. return [self stringByRemovingPercentEncoding];
  126. } else {
  127. #pragma clang diagnostic push
  128. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  129. CFStringEncoding en = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding);
  130. NSString *decoded = [self stringByReplacingOccurrencesOfString:@"+"
  131. withString:@" "];
  132. decoded = (__bridge_transfer NSString *)
  133. CFURLCreateStringByReplacingPercentEscapesUsingEncoding(
  134. NULL,
  135. (__bridge CFStringRef)decoded,
  136. CFSTR(""),
  137. en);
  138. return decoded;
  139. #pragma clang diagnostic pop
  140. }
  141. }
  142. - (NSString *)stringByEscapingHTML {
  143. NSUInteger len = self.length;
  144. if (!len) return self;
  145. unichar *buf = malloc(sizeof(unichar) * len);
  146. if (!buf) return self;
  147. [self getCharacters:buf range:NSMakeRange(0, len)];
  148. NSMutableString *result = [NSMutableString string];
  149. for (int i = 0; i < len; i++) {
  150. unichar c = buf[i];
  151. NSString *esc = nil;
  152. switch (c) {
  153. case 34: esc = @"&quot;"; break;
  154. case 38: esc = @"&amp;"; break;
  155. case 39: esc = @"&apos;"; break;
  156. case 60: esc = @"&lt;"; break;
  157. case 62: esc = @"&gt;"; break;
  158. default: break;
  159. }
  160. if (esc) {
  161. [result appendString:esc];
  162. } else {
  163. CFStringAppendCharacters((CFMutableStringRef)result, &c, 1);
  164. }
  165. }
  166. free(buf);
  167. return result;
  168. }
  169. - (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode {
  170. CGSize result;
  171. if (!font) font = [UIFont systemFontOfSize:12];
  172. if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
  173. NSMutableDictionary *attr = [NSMutableDictionary new];
  174. attr[NSFontAttributeName] = font;
  175. if (lineBreakMode != NSLineBreakByWordWrapping) {
  176. NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
  177. paragraphStyle.lineBreakMode = lineBreakMode;
  178. attr[NSParagraphStyleAttributeName] = paragraphStyle;
  179. }
  180. CGRect rect = [self boundingRectWithSize:size
  181. options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
  182. attributes:attr context:nil];
  183. result = rect.size;
  184. } else {
  185. #pragma clang diagnostic push
  186. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  187. result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
  188. #pragma clang diagnostic pop
  189. }
  190. return result;
  191. }
  192. - (CGFloat)widthForFont:(UIFont *)font {
  193. CGSize size = [self sizeForFont:font size:CGSizeMake(HUGE, HUGE) mode:NSLineBreakByWordWrapping];
  194. return size.width;
  195. }
  196. - (CGFloat)heightForFont:(UIFont *)font width:(CGFloat)width {
  197. CGSize size = [self sizeForFont:font size:CGSizeMake(width, HUGE) mode:NSLineBreakByWordWrapping];
  198. return size.height;
  199. }
  200. - (BOOL)matchesRegex:(NSString *)regex options:(NSRegularExpressionOptions)options {
  201. NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:NULL];
  202. if (!pattern) return NO;
  203. return ([pattern numberOfMatchesInString:self options:0 range:NSMakeRange(0, self.length)] > 0);
  204. }
  205. - (void)enumerateRegexMatches:(NSString *)regex
  206. options:(NSRegularExpressionOptions)options
  207. usingBlock:(void (^)(NSString *match, NSRange matchRange, BOOL *stop))block {
  208. if (regex.length == 0 || !block) return;
  209. NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil];
  210. if (!regex) return;
  211. [pattern enumerateMatchesInString:self options:kNilOptions range:NSMakeRange(0, self.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
  212. block([self substringWithRange:result.range], result.range, stop);
  213. }];
  214. }
  215. - (NSString *)stringByReplacingRegex:(NSString *)regex
  216. options:(NSRegularExpressionOptions)options
  217. withString:(NSString *)replacement; {
  218. NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil];
  219. if (!pattern) return self;
  220. return [pattern stringByReplacingMatchesInString:self options:0 range:NSMakeRange(0, [self length]) withTemplate:replacement];
  221. }
  222. - (char)charValue {
  223. return self.numberValue.charValue;
  224. }
  225. - (unsigned char) unsignedCharValue {
  226. return self.numberValue.unsignedCharValue;
  227. }
  228. - (short) shortValue {
  229. return self.numberValue.shortValue;
  230. }
  231. - (unsigned short) unsignedShortValue {
  232. return self.numberValue.unsignedShortValue;
  233. }
  234. - (unsigned int) unsignedIntValue {
  235. return self.numberValue.unsignedIntValue;
  236. }
  237. - (long) longValue {
  238. return self.numberValue.longValue;
  239. }
  240. - (unsigned long) unsignedLongValue {
  241. return self.numberValue.unsignedLongValue;
  242. }
  243. - (unsigned long long) unsignedLongLongValue {
  244. return self.numberValue.unsignedLongLongValue;
  245. }
  246. - (NSUInteger) unsignedIntegerValue {
  247. return self.numberValue.unsignedIntegerValue;
  248. }
  249. + (NSString *)stringWithUUID {
  250. CFUUIDRef uuid = CFUUIDCreate(NULL);
  251. CFStringRef string = CFUUIDCreateString(NULL, uuid);
  252. CFRelease(uuid);
  253. return (__bridge_transfer NSString *)string;
  254. }
  255. + (NSString *)stringWithUTF32Char:(UTF32Char)char32 {
  256. char32 = NSSwapHostIntToLittle(char32);
  257. return [[NSString alloc] initWithBytes:&char32 length:4 encoding:NSUTF32LittleEndianStringEncoding];
  258. }
  259. + (NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length {
  260. return [[NSString alloc] initWithBytes:(const void *)char32
  261. length:length * 4
  262. encoding:NSUTF32LittleEndianStringEncoding];
  263. }
  264. - (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block {
  265. NSString *str = self;
  266. if (range.location != 0 || range.length != self.length) {
  267. str = [self substringWithRange:range];
  268. }
  269. NSUInteger len = [str lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
  270. UTF32Char *char32 = (UTF32Char *)[str cStringUsingEncoding:NSUTF32LittleEndianStringEncoding];
  271. if (len == 0 || char32 == NULL) return;
  272. NSUInteger location = 0;
  273. BOOL stop = NO;
  274. NSRange subRange;
  275. UTF32Char oneChar;
  276. for (NSUInteger i = 0; i < len; i++) {
  277. oneChar = char32[i];
  278. subRange = NSMakeRange(location, oneChar > 0xFFFF ? 2 : 1);
  279. block(oneChar, subRange, &stop);
  280. if (stop) return;
  281. location += subRange.length;
  282. }
  283. }
  284. - (NSString *)stringByTrim {
  285. NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
  286. return [self stringByTrimmingCharactersInSet:set];
  287. }
  288. - (NSString *)stringByAppendingNameScale:(CGFloat)scale {
  289. if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy;
  290. return [self stringByAppendingFormat:@"@%@x", @(scale)];
  291. }
  292. - (NSString *)stringByAppendingPathScale:(CGFloat)scale {
  293. if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy;
  294. NSString *ext = self.pathExtension;
  295. NSRange extRange = NSMakeRange(self.length - ext.length, 0);
  296. if (ext.length > 0) extRange.location -= 1;
  297. NSString *scaleStr = [NSString stringWithFormat:@"@%@x", @(scale)];
  298. return [self stringByReplacingCharactersInRange:extRange withString:scaleStr];
  299. }
  300. - (CGFloat)pathScale {
  301. if (self.length == 0 || [self hasSuffix:@"/"]) return 1;
  302. NSString *name = self.stringByDeletingPathExtension;
  303. __block CGFloat scale = 1;
  304. [name enumerateRegexMatches:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines usingBlock: ^(NSString *match, NSRange matchRange, BOOL *stop) {
  305. scale = [match substringWithRange:NSMakeRange(1, match.length - 2)].doubleValue;
  306. }];
  307. return scale;
  308. }
  309. - (BOOL)isNotBlank {
  310. NSCharacterSet *blank = [NSCharacterSet whitespaceAndNewlineCharacterSet];
  311. for (NSInteger i = 0; i < self.length; ++i) {
  312. unichar c = [self characterAtIndex:i];
  313. if (![blank characterIsMember:c]) {
  314. return YES;
  315. }
  316. }
  317. return NO;
  318. }
  319. - (BOOL)containsString:(NSString *)string {
  320. if (string == nil) return NO;
  321. return [self rangeOfString:string].location != NSNotFound;
  322. }
  323. - (BOOL)containsCharacterSet:(NSCharacterSet *)set {
  324. if (set == nil) return NO;
  325. return [self rangeOfCharacterFromSet:set].location != NSNotFound;
  326. }
  327. - (NSNumber *)numberValue {
  328. return [NSNumber numberWithString:self];
  329. }
  330. - (NSData *)dataValue {
  331. return [self dataUsingEncoding:NSUTF8StringEncoding];
  332. }
  333. - (NSRange)rangeOfAll {
  334. return NSMakeRange(0, self.length);
  335. }
  336. - (id)jsonValueDecoded {
  337. return [[self dataValue] jsonValueDecoded];
  338. }
  339. + (NSString *)stringNamed:(NSString *)name {
  340. NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@""];
  341. NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
  342. if (!str) {
  343. path = [[NSBundle mainBundle] pathForResource:name ofType:@"txt"];
  344. str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
  345. }
  346. return str;
  347. }
  348. @end