Updated whitesplace-splitting methods

This commit is contained in:
achmizs 2021-12-04 14:59:54 -05:00
parent 9a4c967034
commit e4e7f5a71a
2 changed files with 96 additions and 54 deletions

View File

@ -36,14 +36,15 @@
#pragma mark - Trimming #pragma mark - Trimming
/**********************/ /**********************/
/* “Smart” trimming.
*/
typedef NS_OPTIONS(NSUInteger, SA_NSStringTrimmingOptions) { typedef NS_OPTIONS(NSUInteger, SA_NSStringTrimmingOptions) {
SA_NSStringTrimming_CollapseWhitespace = 1 << 0, SA_NSStringTrimming_CollapseWhitespace = 1 << 0,
SA_NSStringTrimming_TrimWhitespace = 1 << 1, SA_NSStringTrimming_TrimWhitespace = 1 << 1,
SA_NSStringTrimming_AppendEllipsis = 1 << 2, SA_NSStringTrimming_AppendEllipsis = 1 << 2,
SA_NSStringTrimming_ElideEllipsisWhenEmpty = 1 << 3 SA_NSStringTrimming_ElideEllipsisWhenEmpty = 1 << 3
}; };
/* “Smart” trimming.
*/
-(NSString *) stringByTrimmingToMaxLengthInBytes:(NSUInteger)maxLengthInBytes -(NSString *) stringByTrimmingToMaxLengthInBytes:(NSUInteger)maxLengthInBytes
usingEncoding:(NSStringEncoding)encoding usingEncoding:(NSStringEncoding)encoding
withStringEnumerationOptions:(NSStringEnumerationOptions)enumerationOptions withStringEnumerationOptions:(NSStringEnumerationOptions)enumerationOptions
@ -118,6 +119,8 @@ typedef NS_OPTIONS(NSUInteger, SA_NSStringTrimmingOptions) {
*/ */
-(NSArray <NSString *> *) componentsSplitByWhitespace; -(NSArray <NSString *> *) componentsSplitByWhitespace;
-(NSArray <NSString *> *) componentsSplitByWhitespaceWithMaxSplits:(NSUInteger)maxSplits; -(NSArray <NSString *> *) componentsSplitByWhitespaceWithMaxSplits:(NSUInteger)maxSplits;
-(NSArray <NSString *> *) componentsSplitByWhitespaceWithMaxSplits:(NSUInteger)maxSplits
dropEmptyString:(BOOL)dropEmptyString;
/* Splitting by specified delimiter string. /* Splitting by specified delimiter string.
*/ */

View File

@ -332,66 +332,105 @@ static BOOL _SA_NSStringExtensions_RaiseRegularExpressionCreateException = YES;
/***********************/ /***********************/
-(NSArray <NSString *> *) componentsSplitByWhitespace { -(NSArray <NSString *> *) componentsSplitByWhitespace {
return [self componentsSplitByWhitespaceWithMaxSplits:NSUIntegerMax]; return [self componentsSplitByWhitespaceWithMaxSplits:NSUIntegerMax
dropEmptyString:YES];
} }
-(NSArray <NSString *> *) componentsSplitByWhitespaceWithMaxSplits:(NSUInteger)maxSplits { -(NSArray <NSString *> *) componentsSplitByWhitespaceWithMaxSplits:(NSUInteger)maxSplits {
if (maxSplits == 0) { return [self componentsSplitByWhitespaceWithMaxSplits:maxSplits
return @[ self ]; dropEmptyString:YES];
} }
-(NSArray <NSString *> *) componentsSplitByWhitespaceWithMaxSplits:(NSUInteger)maxSplits
dropEmptyString:(BOOL)dropEmptyString {
// No need to do anything fancy in this case.
if (maxSplits == 0)
return @[ self ];
static NSRegularExpression *regexp;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
regexp = [@"(?:^|\\S|$)+" regularExpression];
});
NSMutableArray <NSString *> *components = [NSMutableArray array]; NSMutableArray <NSString *> *components = [NSMutableArray array];
[regexp enumerateMatchesInString:self
__block NSUInteger tokenStart; options:(NSMatchingOptions) 0
__block NSUInteger tokenEnd; range:self.fullRange
__block BOOL currentlyInToken = NO; usingBlock:^(NSTextCheckingResult * _Nullable result,
__block NSRange tokenRange = NSMakeRange(NSNotFound, 0); NSMatchingFlags flags,
BOOL * _Nonnull stop) {
__block NSUInteger splits = 0; if ( dropEmptyString
&& result.range.length == 0) {
[self enumerateSubstringsInRange:self.fullRange // Nothing.
options:NSStringEnumerationByComposedCharacterSequences } else if (components.count < maxSplits) {
usingBlock:^(NSString *character, [components addObject:[self substringWithRange:result.range]];
NSRange characterRange, } else {
NSRange enclosingRange, [components addObject:[self substringWithRange:[self rangeToEndFrom:result.range]]];
BOOL *stop) {
if ( currentlyInToken == NO
&& [character containsCharactersInSet:[[NSCharacterSet whitespaceCharacterSet] invertedSet]]
) {
currentlyInToken = YES;
tokenStart = characterRange.location;
} else if ( currentlyInToken == YES
&& [character containsCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
) {
currentlyInToken = NO;
tokenEnd = characterRange.location;
tokenRange = NSMakeRange(tokenStart, tokenEnd - tokenStart);
[components addObject:[self substringWithRange:tokenRange]];
splits++;
if (splits == maxSplits) {
*stop = YES; *stop = YES;
NSRange lastTokenRange = [self rangeToEndFrom:[self firstNonWhitespaceAfterRange:tokenRange]];
if (lastTokenRange.location != NSNotFound) {
[components addObject:[self substringWithRange:lastTokenRange]];
}
}
} }
}]; }];
// If we were in a token when we got to the end, add that last token.
if ( splits < maxSplits
&& currentlyInToken == YES) {
tokenEnd = self.length;
tokenRange = NSMakeRange(tokenStart,
tokenEnd - tokenStart);
[components addObject:[self substringWithRange:tokenRange]];
}
return components; return components;
} }
//-(NSArray <NSString *> *) componentsSplitByWhitespaceWithMaxSplits:(NSUInteger)maxSplits {
// if (maxSplits == 0) {
// return @[ self ];
// }
//
// NSMutableArray <NSString *> *components = [NSMutableArray array];
//
// __block NSUInteger tokenStart;
// __block NSUInteger tokenEnd;
// __block BOOL currentlyInToken = NO;
// __block NSRange tokenRange = NSMakeRange(NSNotFound, 0);
//
// __block NSUInteger splits = 0;
//
// [self enumerateSubstringsInRange:self.fullRange
// options:NSStringEnumerationByComposedCharacterSequences
// usingBlock:^(NSString *character,
// NSRange characterRange,
// NSRange enclosingRange,
// BOOL *stop) {
// if ( currentlyInToken == NO
// && [character containsCharactersInSet:[[NSCharacterSet whitespaceCharacterSet] invertedSet]]
// ) {
// currentlyInToken = YES;
// tokenStart = characterRange.location;
// } else if ( currentlyInToken == YES
// && [character containsCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
// ) {
// currentlyInToken = NO;
// tokenEnd = characterRange.location;
//
// tokenRange = NSMakeRange(tokenStart,
// tokenEnd - tokenStart);
// [components addObject:[self substringWithRange:tokenRange]];
// splits++;
// if (splits == maxSplits) {
// *stop = YES;
// NSRange lastTokenRange = [self rangeToEndFrom:[self firstNonWhitespaceAfterRange:tokenRange]];
// if (lastTokenRange.location != NSNotFound) {
// [components addObject:[self substringWithRange:lastTokenRange]];
// }
// }
// }
// }];
//
// // If we were in a token when we got to the end, add that last token.
// if ( splits < maxSplits
// && currentlyInToken == YES) {
// tokenEnd = self.length;
//
// tokenRange = NSMakeRange(tokenStart,
// tokenEnd - tokenStart);
// [components addObject:[self substringWithRange:tokenRange]];
// }
//
// return components;
//}
-(NSArray <NSString *> *) componentsSeparatedByString:(NSString *)separator -(NSArray <NSString *> *) componentsSeparatedByString:(NSString *)separator
maxSplits:(NSUInteger)maxSplits { maxSplits:(NSUInteger)maxSplits {
NSArray <NSString *> *components = [self componentsSeparatedByString:separator]; NSArray <NSString *> *components = [self componentsSeparatedByString:separator];