tyeen
tyeen

Reputation: 33

Swift distance() method throws fatal error: can not increment endIndex

I was trying to find a substring match in a string, and get the matched position.

I can't figure out what's wrong with the following code:

let str1 = "hello#゚Д゚"
let cmp = "゚Д゚"
let searchRange = Range(start: str1.startIndex, end: str1.endIndex)
let range = str1.rangeOfString(cmp, options: .allZeros, range: searchRange)

println("\(searchRange), \(range!)") // output: 0..<9, 6..<9

let dis = distance(searchRange.startIndex, range!.startIndex) // fatal error: can not increment endIndex! reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
// let dis = distance(searchRange.startIndex, range!.endIndex) // This will go and output: distance=7

println("distance=\(dis)")

As the comments suggested, although the range had valid values, the distance() method threw a fatal error.

If I'm wrong about the use of distance(), what method should I use to archive the target? Any advice would be helpful. Thanks.

Upvotes: 3

Views: 5599

Answers (2)

Daniel T.
Daniel T.

Reputation: 33967

Try this:

func search<C: CollectionType where C.Generator.Element: Equatable>(col1: C, col2: C) -> C.Index? {
    if col2.startIndex == col2.endIndex {
        return col1.startIndex
    }

    var col1Ind = col1.startIndex
    while col1Ind != col1.endIndex {
        var ind1 = col1Ind
        var ind2 = col2.startIndex
        while col1[ind1] == col2[ind2] {
            ++ind1; ++ind2
            if ind2 == col2.endIndex { return col1Ind }
            if ind1 == col1.endIndex { return nil }
        }
        ++col1Ind
    }
    return nil
}

Searches for the first instance of the col2 sequence in col1. If found, returns the index of the start of the sub-sequence. If not found, returns nil. If col2 is empty, returns the startIndex of col1.

Upvotes: 1

rintaro
rintaro

Reputation: 51911

range!.startIndex points here:

"hello#゚Д゚"
       ^

But, in this case, #゚ is a single character in Swift.

Therefore, This code:

for var idx = searchRange.startIndex; idx != range!.startIndex; idx = idx.successor() {
    println("\(idx): \(str1[idx])");
}

prints:

0: h
1: e
2: l
3: l
4: o
5: #゚
7: Д゚
fatal error: Can't form a Character from an empty String
// and emits BAD_INSTRUCTION exception

As you can see range!.startIndex never matches to the character boundaries, and the for loop run out the string. That's why you see the exception.

In theory, since String is considered as "Collection of Characters" in Swift, "゚Д゚" should not be a substring of "hello#゚Д゚".

I think .rangeOfString() uses NSString implementation which treats string as a sequence of unichar. I don't know this should be considered as a bug or not.

Upvotes: 3

Related Questions