获取两个NSString之间的差异

4

我有两个NSString字符串,我想要找出它们之间的差异。

下面给一个例子:

NSString *pippo = @"pippo";
NSString *pippone = @"pippone";

我想获得两个实例中的不同字符,应该如何操作?


3
我开始回答你的问题,但后来意识到为了给出最好的答案,需要知道更多的细节。例如,如果字符串一是"meat",另一个是"spicy meatball",你想要的区别是"辣肉丸"还是两个句子之间不同的字母,如{s,p,i,c,y,b,l}? - Michael Dautermann
3
你如何定义字符串之间的区别?你在这里所表达的,是一个字符串在末尾增加了额外字符的情况吗?或者,比如说,你会如何考虑 pippopissone 之间的区别? 您好,对于字符串之间的区别,是否存在取决于具体情况。一个字符串在末尾增加了额外字符是一种区别字符串的可能性,但并不是唯一的方式。例如,pippopissone 这两个字符串之间的区别是它们中间的字母不同。 - FluffulousChimp
可能是重复的问题:如何检查两个NSString是否相似 - jscs
3个回答

2

尽管一些特殊情况(例如后缀)可以使用更简单的算法处理,但为了处理一般情况,您可以:

1/ 首先提取一个公共序列。除非您的字符串非常长,否则最长公共子序列算法将是您的选择(LCS,请参见https://en.wikipedia.org/wiki/Longest_common_subsequence_problem)。

您可以在此处找到LCS的obj-c和swift实现:http://jakubturek.pl/blog/2015/06/27/using-swifts-string-type-with-care/

2/ 从LCS中获取差异很容易,例如请参见https://en.wikipedia.org/wiki/Diff_utility。 下面是一个obj-C实现(NSString类别,假设我们有上面链接中的longestCommonSubsequence:):

- (NSArray *) lcsDiff:(NSString *)string
{
    NSString *lcs = [self longestCommonSubsequence:string];
    NSUInteger l1 = [self length];
    NSUInteger l2 = [string length];
    NSUInteger lc = [lcs length];
    NSUInteger idx1 = 0;
    NSUInteger idx2 = 0;
    NSUInteger idxc = 0;
    NSMutableString *s1 = [[NSMutableString alloc]initWithCapacity:l1];
    NSMutableString *s2 = [[NSMutableString alloc]initWithCapacity:l2];
    NSMutableArray *res = [NSMutableArray arrayWithCapacity:10];
    for (;;) {
        if (idxc >= lc) break;
        unichar c1 = [self characterAtIndex:idx1];
        unichar c2 = [string characterAtIndex:idx2];
        unichar cc = [lcs characterAtIndex:idxc];
        if ((c1==cc) && (c2 == cc)) {
            if ([s1 length] || [s2 length]) {
                NSArray *e = @[ s1, s2];
                [res addObject:e];
                s1 = [[NSMutableString alloc]initWithCapacity:l1];
                s2 = [[NSMutableString alloc]initWithCapacity:l1];
            }
            idx1++; idx2++; idxc++;
            continue;
        }
        if (c1 != cc) {
            [s1 appendString:[NSString stringWithCharacters:&c1 length:1]];
            idx1++;
        }
        if (c2 != cc) {
            [s2 appendString:[NSString stringWithCharacters:&c2 length:1]];
            idx2++;
        }
    }
    if (idx1<l1) {
        [s1 appendString:[self substringFromIndex:idx1]];
    }
    if (idx2<l2) {
        [s2 appendString:[string substringFromIndex:idx2]];
    }
    if ([s1 length] || [s2 length]) {
        NSArray *e = @[ s1, s2];
        [res addObject:e];
    }
    return res;
}

该代码将返回一个数组,其中每个元素(string1,string2)表示两个字符串之间的差异,例如:@[ @"abcXefY" lcsDiff:@"aZbcKef"] 将返回@[ @[ @"", @"Z"], @[ @"X", @"K"], @[ @"Y", @""]];


谢谢!这个链接中的 Swift 2.2 版本的最长公共子序列很好用。 在这里可以找到一个不错的 Objective-C 最长公共子串示例。 - Lion

0

你可以使用一些正则表达式:

我曾经编写过这个函数,可以将一个字符串中的另一个字符串替换为你想要的字符串/模式。

-(NSString *)replaceInString:(NSString *)chaine :(NSString *)pattern
             :(NSString *)template
{
NSMutableString *chaineMutable = [[NSMutableString alloc] initWithString:chaine];
NSRegularExpression *regex = [[NSRegularExpression alloc] init];

regex = [NSRegularExpression regularExpressionWithPattern:pattern
             options:NSRegularExpressionCaseInsensitive error:NULL];

[regex replaceMatchesInString:(NSMutableString *)chaineMutable
             options:NSMatchingReportProgress range:NSMakeRange(0, [chaine length])
             withTemplate:template];

NSString *returnedString = [[NSString alloc] initWithString:chaineMutable];

return returnedString;
}

然后你可以调用它:

NSString *difference = [self replaceInString:pippone :pippo :@""];

所以,你将会用“空”的字符串替换在“pippone”中找到的“pippo”,因此结果将是“ne”。

希望这可以帮助到你。


如果不同的字符在开头或结尾,它是有效的,但如果它在中间,则无法给出不同的字符。例如,如果chaine=@"pippone",pattern=@"pipone",则无法给出差异,如:p是不同的。 - Mehul Thakkar

-3

更新的答案:

-(void)getDifferenceBetweenString:(NSString *)firstString secondString:(NSString *)secondString{
    NSString *longerString = @"";
    NSString *shorterString = @"";
    if (firstString.length >= secondString.length) {
        longerString = firstString;
        shorterString = secondString;
    }else{
        longerString = secondString;
        shorterString = firstString;

    }
    NSArray *shorterArray = [self convertToArray:shorterString];
    NSArray *longerArray = [self convertToArray:longerString];
    NSMutableArray *differenceLettersArray = [NSMutableArray new];
    for (NSString * letter in shorterArray) {
        if (![longerString containsString:letter]) {
            if (![differenceLettersArray containsObject:letter]) {
                [differenceLettersArray addObject:letter];

            }
        }
    }


    for (NSString * letter in longerArray) {
        if (![shorterString containsString:letter]) {
            if (![differenceLettersArray containsObject:letter]) {
                [differenceLettersArray addObject:letter];

            }
        }
    }
    NSLog(@"differences = %@",differenceLettersArray);
}

- (NSArray *)convertToArray:(NSString *)string {
    NSMutableArray *arr = [[NSMutableArray alloc] init];
    NSUInteger i = 0;
    while (i < string.length) {
        NSRange range = [string rangeOfComposedCharacterSequenceAtIndex:i];
        NSString *chStr = [string substringWithRange:range];
        [arr addObject:chStr];
        i += range.length;
    }

    return arr;
}

然后按照以下方式使用:

[self getDifferenceBetweenString:@"pippo" secondString:@"pippone"];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接