查找与 NSString 中另一个字符的位置相关的字符的位置

Finding position of a character related to the position of another character in NSString

假设我有一个包含以下数据的 txt 文件;

12345,123,98765,JOHN,RL,s/w
12345,123,98765,SAM,RL,s/w 
12345,123,98765,MIC,RL,s/w
12345,123,98765,MIC,RL,s/w
12345,123,98765,MIC,RL,s/w
12345,123,98765,MIC,RL,s/w
12345,123,98765,MIC,RL,s/w
12345,123,98765,AMI,RL,s/w
12345,123,98765,THIMOTHY,RL,s/w

它捆绑在我的应用程序中,我正在将数据读取到 nsstring。我正在传递一个搜索词,比如 'MIC'。当我传递这个搜索词时,我想获取具有搜索词的行并从字符串中删除所有其他行。

我试过以下代码:

NSString *searchTerm = @"MIC";
    NSRange rangess = [dataToBeParsed rangeOfString:searchTerm];

    NSRange range = [dataToBeParsed rangeOfString:@"" options:NSBackwardsSearch range:rangess];
    NSLog(@"range.location: %lu", range.location);
    NSString *substring = [dataToBeParsed substringFromIndex:range.location+1];
    NSLog(@"substring: \n%@'", substring);

我能够找到搜索词的位置并清除字符串内容直到搜索位置。但是我想得到完整的行。

注意:在我的原始文档中,具有搜索词的行将在文档中连续列出。

请帮忙。

NSString *string        = stringDataToBeParsed;
NSArray *components     = [string componentsSeparatedByString:@"\n"];
NSMutableArray *array   = [NSMutableArray new];

for (NSString *string in components)
{
    if ([string containsString:searchTerm])
    {
        [array addObject:string];
    }
}

NSString *stringWithSearchLinesOnly = [array componentsJoinedByString:@"\n"];

如果上面的速度不够快,那么在 Objective-c 中你真的不能比这更快了:

NSString *string             = stringDataToBeParsed;
NSMutableArray *mutableArray = [NSMutableArray new];

[string enumerateLinesUsingBlock:^(NSString * _Nonnull line, BOOL * _Nonnull stop)
{
    if ([line containsString:searchTerm])
    {
        [mutableArray addObject:line];
    }
}];

NSString *stringWithSearchLinesOnly = [mutableArray componentsJoinedByString:@"\n"];

我假设两件事造成的成本最高:

  • 一次又一次搜索整个字符串

  • 为部分字符串创建实例。

但是,您可以通过在整个字符串上使用范围而不是创建子字符串来摆脱两者:

NSUInteger length = [source length];
NSRange searchRange = NSMakeRange( 0, length );
NSRange hitRange = NSMakeRange( 0, 0 );

// Iterate over the string unless you do not find any hit
while( (hitRange = [source rangeOfString:@"Mic" options:0 range:searchRange]).length != 0)
{
   // hitRange contains the range we found "Mic". We have to enlarge it on both sides to \n
   NSRange lineRange = [source rangeOfString:@"\n" options:NSBackwardSearch range:NSMakeRange( 0, hitRange.location ); // Maybe it is an optimization to cut the range ahead of the hit to the last hit. But since it is a backward search, I do not think that this has any effect.

   // We can enlarge the range to the prev \n:
   hitRange.length = hitRange.range + hitRange.location - lineRange.location +1;

   // Go the the next \n
   lineRange = [source rangeOfString:@"\n" options:0 range:NSMakeRange( hitRange.location+hitRange.length, length-hitRange.location+hitRange.length)];

   hitRange.length = lineRange.location-hitRange.location;

   // Do something with the line
   …

   // Move forward
   searchRange.location = hitRange.location+hitRange.length;
   searchRange.length = length-searchRange.location;
}

在 Safari 中输入,只是为了展示方法。肯定有 +1/-1 个错误,并进行了一些优化以减少对单个字符的搜索。

显然这只适用于结尾和开头有 \n 的情况。如果不是这样,请添加 \n。

我真的不知道,这是否更快。不过,还是值得一试的。

作为补充,您可以在 NSString 的类别中创建一个方法,使用一个块来获取范围。这将使它更通用。

修改后的代码:

NSUInteger length = [dataToBeParsedFirst length];
NSRange searchRange = NSMakeRange( 0, length );
NSRange hitRange = NSMakeRange( 0, 0 );
NSMutableArray *linesArr =[[NSMutableArray alloc]init];

// Iterate over the string unless you do not find any hit
while( (hitRange = [dataToBeParsedFirst rangeOfString:ItemID options:0 range:searchRange]).length != 0)
{
    NSRange lineRange = [dataToBeParsedFirst rangeOfString:@"\n" options:NSBackwardsSearch range:NSMakeRange( 0, hitRange.location )];

    NSRange lineEndRange = [dataToBeParsedFirst rangeOfString:@"\n" options:0 range:NSMakeRange(hitRange.location, 500)];

    NSRange dataRange = NSMakeRange(lineRange.location + lineRange.length, lineEndRange.location - lineRange.location + lineRange.length - 1);

    [linesArr addObject:[[dataToBeParsedFirst substringWithRange:dataRange] substringToIndex:dataRange.length - 1]];

    // Move forward
    searchRange.location = lineEndRange.location+lineEndRange.length;
    searchRange.length = length-searchRange.location;
}

NSString *dataToBeParsed = [[linesArr componentsJoinedByString:@"\n"] stringByAppendingString:@"\n"];