Objective c 正在检查NSString中是否存在平衡分隔符
我的输入(Objective c 正在检查NSString中是否存在平衡分隔符,objective-c,string,cocoa,parsing,nsstring,Objective C,String,Cocoa,Parsing,Nsstring,我的输入(NSString)可以是(“文本”),{(“文本”)}或(“文本”){{“文本”}。在所有这些情况下,我必须确保开始分隔符({)有自己的结束分隔符(}) 例如,{{“text”}应标记为错误 我正在尝试NSScanner来实现这一点,还尝试反转字符串并比较每个字符以查找其对立面,但遇到了一些问题 最好的方法是什么 这是我尝试的最新方式: NSMutableString *reversedString = [NSMutableString string]; NSInteger charI
NSString
)可以是(“文本”)
,{(“文本”)}
或(“文本”){{“文本”}
。在所有这些情况下,我必须确保开始分隔符({
)有自己的结束分隔符(}
)
例如,{{“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");
}
}
NSMutableString*reversedString=[NSMutableString];
NSInteger charIndex=[\u expressionTextField.text length];
而(charIndex>0){
查林德斯--;
NSRange subStrRange=NSMakeRange(charIndex,1);
[reversedString appendString:[\u expressionTextField.text substringWithRange:SubStrange]];
}
NSString*mystring=\u expressionTextField.text;
NSLog(@“%@”,反向字符串);
for(int i=0;i
您必须跟踪最新的分隔符符号及其出现
你可以给我们一个堆栈:通过每个在上面找到的开始分隔符。当你找到正确的结束分隔符时,删除最后一个
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSMutableArray *stack = [NSMutableArray array];
NSString *text = @"(“text”){{“text”}}}";
NSArray *delimiterPairs = @[@[@"(", @")"],@[@"{", @"}"]];
NSMutableString *openingDelimiters = [@"" mutableCopy];
NSMutableString *closingDelimiters = [@"" mutableCopy];
[delimiterPairs enumerateObjectsUsingBlock:^(NSArray *pair, NSUInteger idx, BOOL *stop) {
[openingDelimiters appendString:pair[0]];
[closingDelimiters appendString:pair[1]];
}];
NSScanner *scanner = [NSScanner scannerWithString:text];
__block BOOL unbalanced = NO;
while (![scanner isAtEnd] && !unbalanced) {
[scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:[openingDelimiters stringByAppendingString:closingDelimiters]]
intoString:NULL];
NSString *currentDelimiter = [text substringWithRange:NSMakeRange([scanner scanLocation], 1)];
if ([openingDelimiters rangeOfString:currentDelimiter].location != NSNotFound) {
[stack addObject:currentDelimiter];
} else {
[delimiterPairs enumerateObjectsUsingBlock:^(NSArray *pair, NSUInteger idx, BOOL *stop) {
if([currentDelimiter isEqualToString:pair[1]]){
if([stack count] == 0) {
unbalanced = YES;
} else if ([[stack lastObject] isEqualToString:pair[0]]) {
[stack removeLastObject];
}
*stop = YES;
}
}];
}
scanner.scanLocation +=1;
}
if ([stack count])
unbalanced = YES;
}
return 0;
}
#导入
int main(int argc,const char*argv[]
{
@自动释放池{
NSMutableArray*堆栈=[NSMutableArray];
NSString*text=@(“text”){{{“text”}}};
NSArray*delimiterPairs=@[@[@”(“,@”)”],@[@“{”,“@}”];
NSMutableString*openingDelimiters=[@”“mutableCopy];
NSMutableString*closingDelimiters=[@”“mutableCopy];
[delimiterPairs enumerateObjectsUsingBlock:^(NSArray*对,NSUInteger idx,布尔*停止){
[openingDelimiters appendString:对[0]];
[closingDelimiters-appendString:pair[1]];
}];
NSScanner*scanner=[NSScanner scannerWithString:text];
__块布尔不平衡=否;
而(![scanner isattend]&&!不平衡){
[扫描仪扫描到CharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:[openingDelimiters stringByAppendingString:closingDelimiters]]
intoString:NULL];
NSString*currentDelimiter=[文本子字符串WithRange:NSMakeRange([扫描仪扫描位置],1)];
if([openingDelimiters rangeOfString:currentDelimiter].location!=NSNotFound){
[堆栈添加对象:currentDelimiter];
}否则{
[delimiterPairs enumerateObjectsUsingBlock:^(NSArray*对,NSUInteger idx,布尔*停止){
if([currentDelimiter isEqualToString:对[1]]){
如果([堆栈计数]==0){
不平衡=是;
}如果([[stack lastObject]IsequalString:对[0]]),则为else{
[堆栈移除对象];
}
*停止=是;
}
}];
}
scanner.scanLocation+=1;
}
如果([堆栈计数])
不平衡=是;
}
返回0;
}
如果分隔符不匹配,bool将为YES 我用
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;
}
我向NSScanner添加了一个方法,使我的生活更轻松。这样我们就不必扫描一堆字符(因为分隔符可以彼此相邻),然后将它们拆分为单独的NSString
s
@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
一些测试:
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);
}
除了简单计数外,是否还要确保嵌套对按打开顺序关闭?因此,
{(“文本)”}
将是无效的?@JoshCaswell-检查我的编辑。我真的不明白你的反向字符串想法是怎么回事。您需要确保(
附带)
——这是两个不同的字符,不会进行相等的比较——不仅仅是存在“括号”。我认为NSScanner
是正确的选择,(我现在没有时间去摆弄它)。您还可以粗略地看一眼,在字符串中移动,根据您遇到的开场白保留您希望看到的结束字符的列表(堆栈)。如果你得到一个不正常的,失败,否则成功。谢谢你发布这个代码。它非常有用。然而,我发现它的一个问题是,如果你有一个字符串,比如“This is today's午餐”,它应该平衡,因为文本周围的双引号完成了字符串,即使在“today's”中有一个单引号。但是,即使字符串中有一个双引号,“这是今天的午餐”也应该进行验证。两边的单引号都可以。知道如何处理吗?这听起来很难以一般方式进行验证。如果你想在找到一个开口“
”后忽略任何其他分隔符,然后您可以scanuptString:intoString:
直接跳到结束分隔符或字符串末尾。另一个选择是对有效收缩进行特殊处理。也就是说,如果在'
之后找到s
,则从分隔符堆栈中弹出'
,然后继续。