简体   繁体   中英

Comparing String.Index values

Is it possible to compare two String.Index values in Swift? I'm trying to process a string character by character, and several times I need to check if I am at the end of the string. I've tried just doing

while (currentIndex < string.endIndex) {
    //do things...
    currentIndex = currentIndex.successor()
}

Which complained about type conversions. Then, I tried defining and overload for < as such:

@infix func <(lhs: String.Index, rhs: String.Index) -> Bool {
    var ret = true //what goes here?
    return ret
}

Which gets rid of compilation errors, but I have no clue what to do in order to compare lhs and rhs properly. Is this the way I should go about using String.Index , or is there a better way to compare them?

String indexes support = and != . String indexes are an opaque type, not integers and can not be compared like integers.

Use: if (currentIndex != string.endIndex)

var currentIndex = string.startIndex
while (currentIndex != string.endIndex) {
    println("currentIndex: \(currentIndex)")
    currentIndex = currentIndex.successor()
}

The simplest option is the distance() function:

var string = "Hello World"
var currentIndex = string.startIndex

while (distance(currentIndex, string.endIndex) >= 0) {
  println("currentIndex: \(currentIndex)")
  currentIndex = currentIndex.successor()
}

Beware distance() has O(N) performance, so avoid it for large strings. However, the entire String class doesn't currently handle large strings anyway — you should probably switch to CFString if performance is critical.

Using an operator overload is a bad idea, but just as a learning exercise this is how you'd do it:

var string = "Hello World"
var currentIndex = string.startIndex

@infix func <(lhs: String.Index, rhs: String.Index) -> Bool {
  return distance(lhs, rhs) > 0
}

while (currentIndex < string.endIndex) {
  currentIndex = currentIndex.successor()
}

I believe this REPL/Playground example should illuminate what you (and others) need to know about working with the String.Index concept.

// This will be our working example
let exampleString = "this is a string"

// And here we'll call successor a few times to get an index partway through the example
var someIndexInTheMiddle = exampleString.startIndex
for _ in 1...5 {
    someIndexInTheMiddle = someIndexInTheMiddle.successor()
}

// And here we will iterate that string and detect when our current index is relative in one of three different possible ways to the character selected previously
println("\n\nsomeIndexInTheMiddle = \(exampleString[someIndexInTheMiddle])")
for var index: String.Index = exampleString.startIndex; index != exampleString.endIndex; index = index.successor() {
    println(" - \(exampleString[index])")
    if index != exampleString.startIndex && index.predecessor() == someIndexInTheMiddle {
        println("current character comes after someIndexInTheMiddle")
    } else if index == someIndexInTheMiddle {
        println("current character is the one indicated by someIndexInTheMiddle")
    } else if index != exampleString.endIndex && index.successor() == someIndexInTheMiddle {
        println("Current character comes before someIndexinTheMiddle")
    }
}

Hopefully that provides the necessary information.

Whatever way you decide to iterator over a String , you will immediately want to capture the iteration in a function that can be repeatedly invoked while using a closure applied to each string character. As in:

extension String {
  func each (f: (Character) -> Void) {
    for var index = self.startIndex;
        index < self.endIndex;
        index = index.successor() {
      f (string[index])
    }
  }
}

Apple already provides these for C-Strings and will for general strings as soon as they get character access solidified.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM