检查NSString是否有平衡分隔符

Osc*_*ros 2 string cocoa parsing objective-c nsstring

我的输入(NSString)可以是("text"),{("text")}(“text”){{“text”}}.在所有这些情况下,我必须确保开始分隔符({)获得自己的结束分隔符(}).

例如,{{“text”})应标记为错误.

我正在努力NSScanner实现这一目标,并且还试图反转字符串并比较每个角色寻找相反的情况,但一直遇到一些麻烦.

什么是最好的方法?

这是我尝试过的最新方式:

NSMutableString *reversedString = [NSMutableString string];
NSInteger charIndex = [_expressionTextField.text length];
while (charIndex > 0) {
    charIndex--;
    NSRange subStrRange = NSMakeRange(charIndex, 1);
    [reversedString appendString:[_expressionTextField.text substringWithRange:subStrRange]];
}

NSString *mystring = _expressionTextField.text;

NSLog(@"%@", reversedString);
for (int i = 0; i < reversedString.length; i++) {
    if ([mystring characterAtIndex:i] == [reversedString characterAtIndex:(reversedString.length -i)]) {
        NSLog(@"Closed the bracket");
    }
}
Run Code Online (Sandbox Code Playgroud)

Jos*_*ell 5

使用时,我有一个裂缝NSScanner.我认为这对于非常长的琴弦来说比vikingosegundo快一点,因为我只是一次直接穿过一个角色.没有搜索或子串制作.在大多数情况下,它可能不会有所作为.

/// Takes a string and a dictionary of delimiter pairs in which the keys are the
/// opening characters of the pairs and the values the closers. Returns YES if the 
/// delimiters in the string are balanced, otherwise NO. Ignores any characters
/// not present in the dictionary.
///
/// Note: Does not support multi-character delimiters.
BOOL stringHasBalancedDelimiters(NSString * s, NSDictionary * delimiterPairs)
{
    NSMutableArray * delimiterStack = [NSMutableArray array];

    NSString * openers = [[delimiterPairs allKeys] componentsJoinedByString:@""];
    NSString * closers = [[delimiterPairs allValues] componentsJoinedByString:@""];
    NSCharacterSet * openerSet = [NSCharacterSet characterSetWithCharactersInString:openers];
    NSCharacterSet * closerSet = [NSCharacterSet characterSetWithCharactersInString:closers];
    NSMutableCharacterSet * delimiterSet = [openerSet mutableCopy];
    [delimiterSet formUnionWithCharacterSet:closerSet];

    NSScanner * scanner = [NSScanner scannerWithString:s];

    while( ![scanner isAtEnd] ){

        // Move up to the next delimiter of either kind
        [scanner scanUpToCharactersFromSet:delimiterSet intoString:nil];

        NSString * delimiter;
        // Could be a closer.
        if( [scanner WSSScanSingleCharacterFromSet:closerSet intoString:&delimiter] ){
            // Got a paired closer; pop the opener off the stack and continue.
            NSString * expected = [delimiterStack lastObject];
            if( [expected isEqualToString:delimiter] ){
                [delimiterStack removeLastObject];
                continue;
            }
            // Not the right closer, but if the members of the pair are
            // identical, treat as an opener.
            else if( [delimiterPairs[delimiter] isEqualToString:delimiter] ){
                [delimiterStack addObject:delimiterPairs[delimiter]];
                continue;
            }
            // Otherwise this is a failure.
            else {
                return NO;
            }
        }

        // Otherwise it's an opener (or nothing, thus the if).
        if( [scanner WSSScanSingleCharacterFromSet:openerSet intoString:&delimiter] ){
            [delimiterStack addObject:delimiterPairs[delimiter]];
        }
    }

    // Haven't failed and nothing left to pair? Success.
    return [delimiterStack count] == 0;
}
Run Code Online (Sandbox Code Playgroud)

我添加了一种NSScanner让我的生活更轻松的方法.这样我们就不必扫描一堆字符(因为分隔符可以彼此相邻),然后将它们拆分成单独的NSStrings.

@interface NSScanner (WSSSingleCharacter)

- (BOOL)WSSScanSingleCharacterFromSet:(NSCharacterSet *)charSet intoString:(NSString * __autoreleasing *)string;

@end

@implementation NSScanner (WSSSingleCharacter)

- (BOOL)WSSScanSingleCharacterFromSet:(NSCharacterSet *)charSet intoString:(NSString *__autoreleasing *)string
{
    if( [self isAtEnd] ) return NO;

    NSUInteger loc = [self scanLocation];
    unichar character = [[self string] characterAtIndex:loc];

    if( [charSet characterIsMember:character] ){
        if( string ){
            *string = [NSString stringWithCharacters:&character length:1];
        }
        [self setScanLocation:loc+1];
        return YES;
    }
    else {
        return NO;
    }
}

@end
Run Code Online (Sandbox Code Playgroud)

一些测试:

NSDictionary * delimiterPairs = @{@"{" : @"}",
                                  @"[" : @"]",
                                  @"\"" : @"\"",
                                  @"'" : @"'",
                                  @"(" : @")"};
// Balanced simple nesting
NSString * s = @"{(\"text\")}";
// Balanced complex nesting
NSString * t = @"{({}'(text)[\"\"]')text}";
// Balanced symmetrical delimiters at beginning and end of string, as
// well as after both an opener and closer from a different pair
NSString * u = @"\"\"(\"text\"\"\")\"\"";
// Out of order
NSString * v = @"{(\"text)\"}";
// Unpaired at the beginning
NSString * w = @"\"{text}";
// Unpaired at the end
NSString * x = @"\"'text'\"(";
// Unpaired in the middle
NSString * y = @"[(text)']";

for( NSString * string in @[s, t, u, v, w, x, y] ){
    BOOL paired = stringHasBalancedDelimiters(string, delimiterPairs);
    NSLog(@"%d", paired);
}
Run Code Online (Sandbox Code Playgroud)