您的当前位置:首页正文

YYKit源码探究(七) —— NSString分类之Utili

来源:花图问答

版本记录

版本号 时间
V1.0 2018.03.20

前言

回顾

上一篇我们分析了NSString分类NSString+YYAddNSNumber Compatible部分,这一篇我们就看一下Utilities部分。


API 接口

下面我们看一下API接口。

/**
 Returns a new UUID NSString
 e.g. "D1178E50-2A4D-4F1F-9BD3-F6AAB00E06B1"
 */
+ (NSString *)stringWithUUID;

/**
 Returns a string containing the characters in a given UTF32Char.
 
 @param char32 A UTF-32 character.
 @return A new string, or nil if the character is invalid.
 */
+ (nullable NSString *)stringWithUTF32Char:(UTF32Char)char32;

/**
 Returns a string containing the characters in a given UTF32Char array.
 
 @param char32 An array of UTF-32 character.
 @param length The character count in array.
 @return A new string, or nil if an error occurs.
 */
+ (nullable NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length;

/**
 Enumerates the unicode characters (UTF-32) in the specified range of the string.
 
 @param range The range within the string to enumerate substrings.
 @param block The block executed for the enumeration. The block takes four arguments:
    char32: The unicode character.
    range: The range in receiver. If the range.length is 1, the character is in BMP;
        otherwise (range.length is 2) the character is in none-BMP Plane and stored
        by a surrogate pair in the receiver.
    stop: A reference to a Boolean value that the block can use to stop the enumeration 
        by setting *stop = YES; it should not touch *stop otherwise.
 */
- (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block;

/**
 Trim blank characters (space and newline) in head and tail.
 @return the trimmed string.
 */
- (NSString *)stringByTrim;

/**
 Add scale modifier to the file name (without path extension),
 From @"name" to @"name@2x".
 
 e.g.
 <table>
 <tr><th>Before     </th><th>After(scale:2)</th></tr>
 <tr><td>"icon"     </td><td>"icon@2x"     </td></tr>
 <tr><td>"icon "    </td><td>"icon @2x"    </td></tr>
 <tr><td>"icon.top" </td><td>"icon.top@2x" </td></tr>
 <tr><td>"/p/name"  </td><td>"/p/name@2x"  </td></tr>
 <tr><td>"/path/"   </td><td>"/path/"      </td></tr>
 </table>
 
 @param scale Resource scale.
 @return String by add scale modifier, or just return if it's not end with file name.
 */
- (NSString *)stringByAppendingNameScale:(CGFloat)scale;

/**
 Add scale modifier to the file path (with path extension),
 From @"name.png" to @"name@2x.png".
 
 e.g.
 <table>
 <tr><th>Before     </th><th>After(scale:2)</th></tr>
 <tr><td>"icon.png" </td><td>"icon@2x.png" </td></tr>
 <tr><td>"icon..png"</td><td>"icon.@2x.png"</td></tr>
 <tr><td>"icon"     </td><td>"icon@2x"     </td></tr>
 <tr><td>"icon "    </td><td>"icon @2x"    </td></tr>
 <tr><td>"icon."    </td><td>"icon.@2x"    </td></tr>
 <tr><td>"/p/name"  </td><td>"/p/name@2x"  </td></tr>
 <tr><td>"/path/"   </td><td>"/path/"      </td></tr>
 </table>
 
 @param scale Resource scale.
 @return String by add scale modifier, or just return if it's not end with file name.
 */
- (NSString *)stringByAppendingPathScale:(CGFloat)scale;

/**
 Return the path scale.
 
 e.g.
 <table>
 <tr><th>Path            </th><th>Scale </th></tr>
 <tr><td>"icon.png"      </td><td>1     </td></tr>
 <tr><td>"icon@2x.png"   </td><td>2     </td></tr>
 <tr><td>"icon@2.5x.png" </td><td>2.5   </td></tr>
 <tr><td>"icon@2x"       </td><td>1     </td></tr>
 <tr><td>"icon@2x..png"  </td><td>1     </td></tr>
 <tr><td>"icon@2x.png/"  </td><td>1     </td></tr>
 </table>
 */
- (CGFloat)pathScale;

/**
 nil, @"", @"  ", @"\n" will Returns NO; otherwise Returns YES.
 */
- (BOOL)isNotBlank;

/**
 Returns YES if the target string is contained within the receiver.
 @param string A string to test the the receiver.
 
 @discussion Apple has implemented this method in iOS8.
 */
- (BOOL)containsString:(NSString *)string;

/**
 Returns YES if the target CharacterSet is contained within the receiver.
 @param set  A character set to test the the receiver.
 */
- (BOOL)containsCharacterSet:(NSCharacterSet *)set;

/**
 Try to parse this string and returns an `NSNumber`.
 @return Returns an `NSNumber` if parse succeed, or nil if an error occurs.
 */
- (nullable NSNumber *)numberValue;

/**
 Returns an NSData using UTF-8 encoding.
 */
- (nullable NSData *)dataValue;

/**
 Returns NSMakeRange(0, self.length).
 */
- (NSRange)rangeOfAll;

/**
 Returns an NSDictionary/NSArray which is decoded from receiver.
 Returns nil if an error occurs.
 
 e.g. NSString: @"{"name":"a","count":2}"  => NSDictionary: @[@"name":@"a",@"count":@2]
 */
- (nullable id)jsonValueDecoded;

/**
 Create a string from the file in main bundle (similar to [UIImage imageNamed:]).
 
 @param name The file name (in main bundle).
 
 @return A new string create from the file in UTF-8 character encoding.
 */
+ (nullable NSString *)stringNamed:(NSString *)name;

1. + (NSString *)stringWithUUID;

该方法返回的是UUID字符串。

示例调用

NSString *resultStr = [NSString stringWithUUID];
NSLog(@"UUID为 = %@", resultStr);

下面看一下输出结果

2018-03-19 14:28:47.932947+0800 JJWebImage[29178:4163246] UUID为 = 03367F43-93A0-41AC-A2AC-650A31F0A40A

方法实现

+ (NSString *)stringWithUUID {
    CFUUIDRef uuid = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, uuid);
    CFRelease(uuid);
    return (__bridge_transfer NSString *)string;
}

2. + (nullable NSString *)stringWithUTF32Char:(UTF32Char)char32;

该方法的作用就是将给定的UTF32Char类型的字符转化为一个NSString类型的字符串,如果这个字符是无效的,那么转化的字符串为nil。

示例调用

下面看一个示例。

UTF32Char number = 97;
NSString *resultStr = [NSString stringWithUTF32Char:number];
NSLog(@"resultStr = %@", resultStr);

下面看一下输出结果

2018-03-19 14:35:36.296366+0800 JJWebImage[29190:4166179] resultStr = a

方法实现

下面看一下该方法的实现

+ (NSString *)stringWithUTF32Char:(UTF32Char)char32 {
    char32 = NSSwapHostIntToLittle(char32);
    return [[NSString alloc] initWithBytes:&char32 length:4 encoding:NSUTF32LittleEndianStringEncoding];
}

上面方法的实现中调用的两个方法均为系统内部的方法。

3. + (nullable NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length;

该方法的作用就是根据给定的 UTF-32字符组和长度,返回一个字符串。

方法实现

下面看一下该方法的实现

+ (NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length {
    return [[NSString alloc] initWithBytes:(const void *)char32
                                    length:length * 4
                                  encoding:NSUTF32LittleEndianStringEncoding];
}

4. - (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block;

枚举字符串指定范围内的Unicode字符(UTF-32),这里需要说明下几个参数:

  • range :字符串在range范围内遍历子字符串。
  • block :执行遍历的块。
    • char32 : unicode字符
    • range :这个是接受者,如果range.length == 1,字符是BMP;否则(range.length == 2),该字符在非BMP平面中,并由代理对存储在接收器中。
    • stop : 一个布尔值的引用,块可以通过设置* stop = YES来停止遍历。

下面看一下该方法的实现

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

5. - (NSString *)stringByTrim;

该方法的作用就是修剪头部和尾部的空白字符(空格和换行符)。

示例调用

下面看一个示例。

NSString *str = @" aaaa ";
NSLog(@"str = %@, length = %ld", str, str.length);
NSString *resultStr = [str stringByTrim];
NSLog(@"resultStr = %@, length = %ld", resultStr, resultStr.length);

下面看一下输出结果

2018-03-19 15:25:58.879383+0800 JJWebImage[29207:4179554] str =  aaaa , length = 6
2018-03-19 15:25:58.879752+0800 JJWebImage[29207:4179554] resultStr = aaaa, length = 4

方法实现

下面看一下该方法的实现

- (NSString *)stringByTrim {
    NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    return [self stringByTrimmingCharactersInSet:set];
}

6. - (NSString *)stringByAppendingNameScale:(CGFloat)scale;

下面我们看一下这个方法

/**
 Add scale modifier to the file name (without path extension),
 From @"name" to @"name@2x".
 
 e.g.
 <table>
 <tr><th>Before     </th><th>After(scale:2)</th></tr>
 <tr><td>"icon"     </td><td>"icon@2x"     </td></tr>
 <tr><td>"icon "    </td><td>"icon @2x"    </td></tr>
 <tr><td>"icon.top" </td><td>"icon.top@2x" </td></tr>
 <tr><td>"/p/name"  </td><td>"/p/name@2x"  </td></tr>
 <tr><td>"/path/"   </td><td>"/path/"      </td></tr>
 </table>
 
 @param scale Resource scale.
 @return String by add scale modifier, or just return if it's not end with file name.
 */
- (NSString *)stringByAppendingNameScale:(CGFloat)scale;

其实,就是实现类似@"name"@"name@2x"这样的功能。

方法实现

下面看一下该方法的实现

- (NSString *)stringByAppendingNameScale:(CGFloat)scale {
    if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy;
    return [self stringByAppendingFormat:@"@%@x", @(scale)];
}

7. - (NSString *)stringByAppendingPathScale:(CGFloat)scale;

看一下这个方法

/**
 Add scale modifier to the file path (with path extension),
 From @"name.png" to @"name@2x.png".
 
 e.g.
 <table>
 <tr><th>Before     </th><th>After(scale:2)</th></tr>
 <tr><td>"icon.png" </td><td>"icon@2x.png" </td></tr>
 <tr><td>"icon..png"</td><td>"icon.@2x.png"</td></tr>
 <tr><td>"icon"     </td><td>"icon@2x"     </td></tr>
 <tr><td>"icon "    </td><td>"icon @2x"    </td></tr>
 <tr><td>"icon."    </td><td>"icon.@2x"    </td></tr>
 <tr><td>"/p/name"  </td><td>"/p/name@2x"  </td></tr>
 <tr><td>"/path/"   </td><td>"/path/"      </td></tr>
 </table>
 
 @param scale Resource scale.
 @return String by add scale modifier, or just return if it's not end with file name.
 */
- (NSString *)stringByAppendingPathScale:(CGFloat)scale;

其实就是实现从@"name.png"@"name@2x.png"这样的类似转化。

方法实现

下面看一下该方法的实现

- (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];
}

8. - (CGFloat)pathScale;

下面我们看一下该方法

/**
 Return the path scale.
 
 e.g.
 <table>
 <tr><th>Path            </th><th>Scale </th></tr>
 <tr><td>"icon.png"      </td><td>1     </td></tr>
 <tr><td>"icon@2x.png"   </td><td>2     </td></tr>
 <tr><td>"icon@2.5x.png" </td><td>2.5   </td></tr>
 <tr><td>"icon@2x"       </td><td>1     </td></tr>
 <tr><td>"icon@2x..png"  </td><td>1     </td></tr>
 <tr><td>"icon@2x.png/"  </td><td>1     </td></tr>
 </table>
 */
- (CGFloat)pathScale;

方法实现

下面看一下该方法的实现

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

9. - (BOOL)isNotBlank;

该方法的作用就是用来判断是否是空白。nil, @"", @" ", @"\n"会返回NO,其他返回YES。

示例调用

下面看一个示例。

NSString *str = @" ";
BOOL isNotBlank = [str isNotBlank];
NSLog(@"isNotBlank = %d", isNotBlank);
NSString *str1 = @"aaaa";
BOOL isNotBlank1 = [str1 isNotBlank];
NSLog(@"isNotBlank1 = %d", isNotBlank1);

下面看一下输出结果

2018-03-19 15:44:04.690104+0800 JJWebImage[29214:4184283] isNotBlank = 0
2018-03-19 15:44:04.690198+0800 JJWebImage[29214:4184283] isNotBlank1 = 1

方法实现

下面看一下该方法的实现

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

10. - (BOOL)containsString:(NSString *)string;

这个方法很好理解,就是判断一个字符串是否包含另外一个字符串。

示例调用

下面看一个示例。

NSString *str = @"abcde";
BOOL isContain = [str containsString:@"a"];
NSLog(@"isContain = %d", isContain);
NSString *str1 = @"abcde";
BOOL isContain1 = [str1 containsString:@"f"];
NSLog(@"isContain = %d", isContain1);

下面我们看一下输出结果

2018-03-19 16:16:17.588977+0800 JJWebImage[29217:4192114] isContain = 1
2018-03-19 16:16:17.589063+0800 JJWebImage[29217:4192114] isContain = 0

方法实现

下面看一下该方法的实现

- (BOOL)containsString:(NSString *)string {
    if (string == nil) return NO;
    return [self rangeOfString:string].location != NSNotFound;
}

11. - (BOOL)containsCharacterSet:(NSCharacterSet *)set;

这个方法的作用就是字符串是否包含某个字符。

示例调用

下面看一个示例。

NSString *str = @"abc de";
BOOL isContain = [str containsCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
NSLog(@"isContain = %d", isContain);
NSString *str1 = @"abcde";
BOOL isContain1 = [str1 containsCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
NSLog(@"isContain1 = %d", isContain1);

下面看一下输出结果

2018-03-19 16:22:55.638426+0800 JJWebImage[29222:4194182] isContain = 1
2018-03-19 16:22:55.638514+0800 JJWebImage[29222:4194182] isContain1 = 0

方法实现

下面看一下该方法的实现

- (BOOL)containsCharacterSet:(NSCharacterSet *)set {
    if (set == nil) return NO;
    return [self rangeOfCharacterFromSet:set].location != NSNotFound;
}

12. - (nullable NSNumber *)numberValue;

这个方法很简单就不举例了,就是将字符串转化为NSNumber数据类型,如果不能转换,就返回nil。

下面看一下方法实现

- (NSNumber *)numberValue {
    return [NSNumber numberWithString:self];
}

13. - (nullable NSData *)dataValue;

这个方法很简单就不举例了,就是将字符串转化为NSData数据类型,使用的是UTF - 8编码。

下面看一下方法实现

- (NSData *)dataValue {
    return [self dataUsingEncoding:NSUTF8StringEncoding];
}

14. - (NSRange)rangeOfAll;

这个方法很简单就不举例了,就是将返回字符串的range - NSMakeRange(0, self.length)

下面我们看一下方法的实现过程。

- (NSRange)rangeOfAll {
    return NSMakeRange(0, self.length);
}

15. - (nullable id)jsonValueDecoded;

该方法的作用就是将指定的Json字符串转化为字典或者数组。

方法实现

下面看一下该方法的实现。

- (id)jsonValueDecoded {
    return [[self dataValue] jsonValueDecoded];
}

下面就是调用NSData分类的这个方法了。

- (id)jsonValueDecoded {
    NSError *error = nil;
    id value = [NSJSONSerialization JSONObjectWithData:self options:kNilOptions error:&error];
    if (error) {
        NSLog(@"jsonValueDecoded error:%@", error);
    }
    return value;
}

16. + (nullable NSString *)stringNamed:(NSString *)name;

该方法的作用就是从main bundle文件中创建字符串,类似于[UIImage imageNamed:]。返回值为文件中UTF - 8编码的字符串。

方法实现

下面看一下该方法的实现。

+ (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;
}

后记

本篇我们分析了Utilities部分的功能,主要就是涉及到字符串处理的一些小的工具,比如获取UUID字符串等,喜欢的给个赞~~~