【问题标题】:Comparing String.Index values比较 String.Index 值
【发布时间】:2014-08-04 00:25:29
【问题描述】:

是否可以在 Swift 中比较两个 String.Index 值?我正在尝试逐个字符地处理字符串,并且有几次我需要检查我是否在字符串的末尾。我试过只是做

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

抱怨类型转换。然后,我尝试为&lt; 定义和重载:

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

这消除了编译错误,但我不知道该怎么做才能正确比较 lhsrhs。这是我应该使用String.Index 的方式,还是有更好的方法来比较它们?

【问题讨论】:

  • 覆盖运算符不是解决方案。
  • 很明显,覆盖&lt; 不会解决任何问题,但这就是我希望能够比较两个String.Index 值的方式,如果可能的话。有没有其他方法可以做到这一点?
  • 在 Swift 3 中,&lt; 似乎有效。

标签: string macos swift


【解决方案1】:

最简单的选项是distance() 函数:

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

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

注意distance() 具有O(N) 的性能,因此请避免使用大字符串。但是,无论如何,整个 String 类目前都不能处理大字符串——如果性能很关键,您可能应该切换到 CFString

使用运算符重载是个坏主意,但作为一个学习练习,你应该这样做:

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()
}

【讨论】:

  • 这就是我想要的。 O(n) 性能有点烦人,但可能不会对我正在使用的字符串造成任何问题。为什么说使用运算符重载是个坏主意?
  • @Jumhyn 注意 String 类目前 full 存在O(n) 性能问题。无论如何,你都会遇到他们。这似乎是该类中的一般设计缺陷。毫无疑问他们有一天会修复它,但现在我们只需要接受它 - 或者使用 NS/CFString。
  • 稍后当其他人处理代码时,他们将无法理解其用法。再加上许多开发人员超载各种事情,这是灾难的根源。最好的解决方案是最清晰的解决方案,即以后会导致更少 WTF/分钟的解决方案。
  • @AbhiBeckert 但是CFStringNSString 在处理表情符号、代理对和诸如标志字符之类的组合时都存在重大问题,这些都不能在 UTF-16 unichar 中表示。表情符号的出现频率越来越高。
  • String.utf16 为您提供了另一种表示形式,它更接近于 NSString 和 CFString 索引的工作方式。您可以使用整数索引并对索引进行数学运算,但是目前它缺少查找和匹配字符串的功能,因此您必须自己实现这些功能。它还受到 NSString 和 CFString 的所有缺点的影响。
【解决方案2】:

字符串索引支持=!=。字符串索引是不透明类型,不是整数,不能像整数一样进行比较。

使用:if (currentIndex != string.endIndex)

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

【讨论】:

  • 我知道这是正确的答案,但作为一个附带问题,有没有办法检查一个索引是否在另一个索引之前或之后?
  • 如果你这样做,你会错过最后一个索引。
  • 如果您只拨打currentIndex.successor,您就不能错过最后一个字符。但请提交错误报告,这是一个测试版。另请注意,Beta4 发生了很大变化,因此很有可能会有改进。整个 unicode 问题仍然存在很多问题,但 Apple 使用 Swift 解决了很多问题。
  • 是的,String 肯定有一些限制。我坚持使用 CFString 的唯一需要执行复杂字符串操作的项目。我怀疑我正在利用的一些更高级的东西永远不可能使用 String。
  • CFString 的问题在于它不能处理表情符号,代理对不是复合的,例如标志字符,它们都不能在 UTF-16 unichar 中表示。跨度>
【解决方案3】:

我相信这个 REPL/Playground 示例应该阐明您(和其他人)在使用 String.Index 概念时需要了解的内容。

// 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")
    }
}

希望能提供必要的信息。

【讨论】:

    【解决方案4】:

    无论您决定以何种方式对String 进行迭代,您都会立即希望在一个函数中捕获迭代,该函数可以在使用应用于每个字符串字符的闭包时重复调用。如:

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

    Apple 已经为 C-Strings 提供了这些,并且一旦它们获得固化的字符访问权限,就会为一般字符串提供这些。

    【讨论】:

      猜你喜欢
      • 2017-01-24
      • 1970-01-01
      • 1970-01-01
      • 2015-09-02
      • 2016-01-14
      • 2021-05-03
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多