Reputation: 33
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
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
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 Character
s" 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