Do these two ranges intersect? If so, how do I kno

2019-08-14 17:33发布

From Apple's documentation:

Return Value A range describing the intersection of range1 and range2—that is, a range containing the indices that exist in both ranges.

Discussion If the returned range’s length field is 0, then the two ranges don’t intersect, and the value of the location field is undefined.

Okay, so let's say I have two ranges:

(lldb) p rangeOne
(NSRange) $3 = location=11, length=4
(lldb) p rangeTwo
(NSRange) $4 = location=14, length=0

And I calculate the intersection:

NSRange intersection = NSIntersectionRange(rangeOne, rangeTwo);

The result is:

(lldb) p intersection
(NSRange) $5 = location=14, length=0

What am I supposed to do with that? Length is zero, so the location is undefined? But in this case, the result is what I would expect; can I trust it? Is calculating the intersection of ranges where one range has a length of zero invalid?

5条回答
啃猪蹄的小仙女
2楼-- · 2019-08-14 18:02

If the returned range’s length field is 0, then the two ranges don’t intersect, and the value of the location field is undefined.

I'd interpret that to mean that when length is 0, the ranges are not intersecting.

BOOL RangesIntersect(NSRange range1, NSRange range2) {
    return NSIntersectionRange(range1, range2).length != 0;
}

Agreed with Tommy – they could have set it to NSNotFound – but instead they say the result is undefined. Furthermore, I agree that the location of a zero-length range is meaningless. The position in rangeTwo doesn't mean anything. Nor can rangeTwo intersect with anything.

查看更多
The star\"
3楼-- · 2019-08-14 18:03

You're right. You have to go with the documentation. The value is unusable. What a hole in the API!


As a quick thought, similar to Tommy's answer, here is a version with a stronger promise

// Like NSIntersectionRange() except it returns location of NSNotFound and
// length of NSNotFound when the ranges do not intersect.
static inline NSRange MyIntersectionRange(NSRange range1, NSRange range2)
{
    if (range1.location == NSNotFound || range1.length == NSNotFound ||
        range2.location == NSNotFound || range2.length == NSNotFound)
        return NSMakeRange(NSNotFound, NSNotFound);

    NSUInteger begin1 = range1.location;
    NSUInteger end1 = range1.location + range1.length;
    NSUInteger begin2 = range2.location;
    NSUInteger end2 = range2.location + range2.length;

    if (end1 <= begin2 || end2 <= begin1)
        return NSMakeRange(NSNotFound, NSNotFound);

    NSUInteger begin = MAX(begin1, begin2);
    NSUInteger end = MIN(end1, end2);

    return NSMakeRange(begin, end - begin);
}

The returned value is the correct answer. You have a range starting at a location of 14 which has a length of 0. A length of 0 does not mean the range is invalid.

Here is an example using a length of 0.

NSString *x = @"abcdefg";
NSString *y = @"123";
NSRange range = NSMakeRange(4, 0);
NSString *z = [x stringByReplacingCharactersInRange:range withString:y];
NSLog(@"%@", z);

results in

2014-06-27 14:29:53.610 TestApp[10501:303] abcd123efg

In this example, the length of 0 means the location is an insertion point and is not removing any of the existing string.

If you need a different answer, then calculate it yourself.

查看更多
Summer. ? 凉城
4楼-- · 2019-08-14 18:04

That's not a bug.. Your range two has 0 length so it is same as none existent... So when you do NSRange intersection = NSIntersectionRange(rangeOne, rangeTwo), of course intersection has length of 0, because you cannot intersect with something that has 0 length!!

查看更多
Animai°情兽
5楼-- · 2019-08-14 18:12

"What am I supposed to do with that?"

NSIntersectionRange is doing its job as intended. If it does not meet your needs, you can write your own.

"Is calculating the intersection of ranges where one range has a length of zero invalid?"

It is not invalid but is it obvious: they don't because they can't.

查看更多
乱世女痞
6楼-- · 2019-08-14 18:20

I don't think NSIntersectionRange exposes that information, which is absurd as they could have set location to NSNotFound or something. So you'd have to do it manually. I doubt you need the exposition, but e.g.:

BOOL NSRangeIntersectsRange(NSRange range1, NSRange range2)
{
    if(range1.location > range2.location + range2.length) return NO;
    if(range2.location > range1.location + range1.length) return NO;
    return YES;
}

(probably with a more appropriate method name prefix than NS)

查看更多
登录 后发表回答