更新: 快速的基准测试显示Matt自己的适应,基于Max和我的方法,效果最佳。
@implementation NSString (TrimmingAdditions)
- (NSString *)stringByTrimmingLeadingCharactersInSet:(NSCharacterSet *)characterSet {
NSUInteger location = 0;
NSUInteger length = [self length];
unichar charBuffer[length];
[self getCharacters:charBuffer];
for (location; location < length; location++) {
if (![characterSet characterIsMember:charBuffer[location]]) {
break;
}
}
return [self substringWithRange:NSMakeRange(location, length - location)];
}
- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet {
NSUInteger location = 0;
NSUInteger length = [self length];
unichar charBuffer[length];
[self getCharacters:charBuffer];
for (length; length > 0; length--) {
if (![characterSet characterIsMember:charBuffer[length - 1]]) {
break;
}
}
return [self substringWithRange:NSMakeRange(location, length - location)];
}
@end
然后:
NSString *trimmedString = [yourString stringByTrimmingTrailingCharactersInSet:[NSCharacterset whitespaceAndNewlineCharacterSet]];
或者针对前导空白符:
NSString *trimmedString = [yourString stringByTrimmingLeadingCharactersInSet:[NSCharacterset whitespaceAndNewlineCharacterSet]];
它的实现是以抽象方式实现的,因此您可以将其与任何可能的NSCharacterSet
一起使用,whitespaceAndNewlineCharacterSet
只是其中之一。
为了方便,您可能想要添加这些包装方法:
- (NSString *)stringByTrimmingLeadingWhitespace {
return [self stringByTrimmingLeadingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
- (NSString *)stringByTrimmingTrailingWhitespace {
return [self stringByTrimmingTrailingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
- (NSString *)stringByTrimmingLeadingWhitespaceAndNewline {
return [self stringByTrimmingLeadingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (NSString *)stringByTrimmingTrailingWhitespaceAndNewline {
return [self stringByTrimmingTrailingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
编辑:为了获得更好的性能,已经恢复使用charBuffer的初始版本。
在@Regexident和@Max的答案基础上,我提出了以下方法:
@implementation NSString (SSToolkitAdditions)
#pragma mark Trimming Methods
- (NSString *)stringByTrimmingLeadingCharactersInSet:(NSCharacterSet *)characterSet {
NSRange rangeOfFirstWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]];
if (rangeOfFirstWantedCharacter.location == NSNotFound) {
return @"";
}
return [self substringFromIndex:rangeOfFirstWantedCharacter.location];
}
- (NSString *)stringByTrimmingLeadingWhitespaceAndNewlineCharacters {
return [self stringByTrimmingLeadingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet {
NSRange rangeOfLastWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]
options:NSBackwardsSearch];
if (rangeOfLastWantedCharacter.location == NSNotFound) {
return @"";
}
return [self substringToIndex:rangeOfLastWantedCharacter.location+1]; // non-inclusive
}
- (NSString *)stringByTrimmingTrailingWhitespaceAndNewlineCharacters {
return [self stringByTrimmingTrailingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
@end
这里是 GHUnit 测试,当然全部通过了:
@interface StringCategoryTest : GHTestCase
@end
@implementation StringCategoryTest
- (void)testStringByTrimmingLeadingCharactersInSet {
NSCharacterSet *letterCharSet = [NSCharacterSet letterCharacterSet];
GHAssertEqualObjects([@"zip90210zip" stringByTrimmingLeadingCharactersInSet:letterCharSet], @"90210zip", nil);
}
- (void)testStringByTrimmingLeadingWhitespaceAndNewlineCharacters {
GHAssertEqualObjects([@"" stringByTrimmingLeadingWhitespaceAndNewlineCharacters], @"", nil);
GHAssertEqualObjects([@"\n \n " stringByTrimmingLeadingWhitespaceAndNewlineCharacters], @"", nil);
GHAssertEqualObjects([@"\n hello \n" stringByTrimmingLeadingWhitespaceAndNewlineCharacters], @"hello \n", nil);
}
- (void)testStringByTrimmingTrailingCharactersInSet {
NSCharacterSet *letterCharSet = [NSCharacterSet letterCharacterSet];
GHAssertEqualObjects([@"zip90210zip" stringByTrimmingTrailingCharactersInSet:letterCharSet], @"zip90210", nil);
}
- (void)testStringByTrimmingTrailingWhitespaceAndNewlineCharacters {
GHAssertEqualObjects([@"" stringByTrimmingLeadingWhitespaceAndNewlineCharacters], @"", nil);
GHAssertEqualObjects([@"\n \n " stringByTrimmingLeadingWhitespaceAndNewlineCharacters], @"", nil);
GHAssertEqualObjects([@"\n hello \n" stringByTrimmingTrailingWhitespaceAndNewlineCharacters], @"\n hello", nil);
}
@end
我提交了一个GitHub拉取请求到SSToolkit,其中添加了这些方法。
NSString* str = @"hdskfh dsakjfh akhf kasdhfk asdfkjash fkadshf1234 ";
NSRange rng = [str rangeOfCharacterFromSet: [NSCharacterSet characterSetWithCharactersInString: [str stringByReplacingOccurrencesOfString: @" " withString: @""]] options: NSBackwardsSearch];
str = [str substringToIndex: rng.location+1];
- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet {
NSRange rangeOfLastWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]
options:NSBackwardsSearch];
if (rangeOfLastWantedCharacter.location == NSNotFound) {
return @"";
}
return [self substringToIndex:rangeOfLastWantedCharacter.location + rangeOfLastWantedCharacter.length]; // non-inclusive
}
characterAtIndex:
方法逐个检索每个字符。链接 - ma11hew28unichar charBuffer
。不知道为什么我放弃了它,转而使用了characterAtIndex:
。我刚做了一个快速基准测试,你的版本比我的初始字节缓冲版本略快。 - RegexidentstringByTrimmingTrailingCharactersInSet:characterSet
,length >= 0
应该改为length> 0
,并且应该删除|| length == 0
吗?否则,当length == 0
时,charBuffer [-1]
将被执行。3)我会使用substringFromIndex
和substringToIndex
而不是substringWithRange
。 - ma11hew28length > 0
是对的,当然。已经修复了。至于它是否支持多字节字符串,我不知道。需要进行一些测试。一些快速基准测试显示,你的代码比我的更优秀。你的代码不会分配额外的内存,支持多字节,并且实际上比我的稍微快一点。老实说,我正在考虑删除我的答案,因为它的投票(与你的答案相比)给出了关于什么是最佳方法的错误印象。而且我认为大多数人不会阅读评论(好吧,反正他们也没什么用,但还是……)。Matt,你支持删除吗? - Regexident