【问题标题】:Find last occurrence of character in String?查找字符串中最后一次出现的字符?
【发布时间】:2015-04-26 23:10:46
【问题描述】:

我想查找字符串中最后一次出现的字符的索引。例如,如果我的字符串是"google.com/program/test",并且我想找到字母/,我希望我的函数返回18,因为这是该字符串中/ 的最后一次出现。我试图关注Finding index of character in Swift String,并且还尝试实现一种方法来遍历字符串并简单地找到具有我想要的字符的字符串的最后一个索引,但advance() 函数似乎抱怨获取整数。

var strCount = 0
var lastSlashIndex = 0
for i in urlAsString {
  if i == "/"{
    if lastSlashIndex < strCount{
      lastSlashIndex = strCount
    }
  }
  strCount++
}

var endOfString = strCount - lastSlash
//Cannot seem to use the advance function to get the remaining substring
var fileName = urlAsString.substringFromIndex(advance(lastSlashIndex, endOfString))

似乎无法弄清楚,任何帮助将不胜感激。

编辑: 这个问题不仅仅针对“/”字符。例如,如果字符串是"abbccd",而我正在寻找字母'c',那么我想返回索引4,因为这是'c' 出现的最后一个索引。

【问题讨论】:

  • 鉴于这个具体的例子,你的问题有点 XY 问题。
  • 对不起,我不是故意的。我想简单地找到特定字符的最后一次出现。它可以是任何字符。例如,如果字符串是“abbccd”并且我正在寻找字母“c”,那么我想返回索引 4,因为这是 c 出现的最后一个索引。@nhgrif
  • 这真的是你想要的吗?还是您实际上是在尝试从看起来像文件路径的字符串中查找文件名?有一个 非常 简单的单线来执行此操作...
  • @nhgrif 好吧,我的问题是这个。我有一个看起来像这样的链接:https://www.dropbox.com/s/s73824fsda/FileName,我只想解析出链接的FileName 部分,以便我可以在我的程序中使用它。如果单线适用于此,我很乐意看到它!

标签: ios string swift


【解决方案1】:

我没有回答标题中的问题,而是查看您的示例代码并假设这是一个 XY 问题。如果您只需要删除最后一个路径组件(或仅检索最后一个路径组件),NSString 上的现有方法可以轻松完成。

如果你想要的只是从路径中提取的文件名:

let path = "/tmp/scratch.tiff"
let fileName = path.lastPathComponent

即使path 看起来像某种 URL,这也有效。

let path = "https://www.dropbox.com/s/s73824fsda/FileName.ext"
let fileName = path.lastPathComponent
println(fileName)

打印出来:

FileName.ext

请注意,无论最后一个路径组件是否具有任何类型的扩展名或其他任何内容,这都有效。 lastPathComponent 只返回最后一个 / 字符之后的所有内容(或者如果没有 /,则返回整个字符串)。

NSString 实际上明确定义了很多用于处理文件路径的方法(这些都适用于 Swift 的String)。我建议看一下official documentation。 NSString 有一整节称为“使用路径”的方法

【讨论】:

  • lastPathComponent 的文档说 Note that this method only works with file paths (not, for example, string representations of URLs).
【解决方案2】:

如果您想查找第一次出现的字符,可以使用 find 函数,因此一个选择是编写一个反向查找等效项,以常规查找为模型,然后使用它:

func rfind
  <C: CollectionType
       where C.Generator.Element: Equatable,
             // one extra constraint needed - the ability
             // to iterate backwards through the collection
             C.Index: BidirectionalIndexType>
  (domain: C, value: C.Generator.Element) -> C.Index? {

    // the wrapping of the indices in reverse() is really
    // the only difference between this and the regular find
    for idx in reverse(indices(domain)) {
        if domain[idx] == value {
            return idx
        }
    }
    return nil
}

鉴于此,很容易使用它来查找由最后一次出现的字符分隔的子字符串:

let path = "/some/path/to/something"

if let firstSlash = rfind(path, "/") {
    let file = path[firstSlash.successor()..<path.endIndex]
    println(file)  // prints “something”
}

当然,如果您不想麻烦地定义泛型函数,您可以直接在代码中编写循环。

注意,虽然 Swift 中的字符串不是通过整数进行随机访问,但这并不重要,因为您无需知道最后一个斜杠是第 n 个字符,只需知道它所在位置的索引。

如果您想假设没有斜杠意味着将整个字符串作为文件名,您可以这样做:

let start = find(path, "/")?.successor() ?? path.startIndex
let file = path[start..<path.endIndex]

【讨论】:

  • 如果我们希望基于/ 以外的任何字符进行此类操作,这个答案非常棒。但是对于/,有一整套用于处理文件路径的方法。
  • 确实,但我选择从字面上解释这个问题:) 主要是因为“如何从文件名中删除路径”这个问题几乎可以肯定是一个骗局......
【解决方案3】:

@Duncan C 建议使用 rangeOfString 函数。

以下是 Swift 2.0 中的示例:

func lastIndexOf(s: String) -> Int? {
    if let r: Range<Index> = self.rangeOfString(s, options: .BackwardsSearch) {
        return self.startIndex.distanceTo(r.startIndex)
    }

     return Optional<Int>()
}

测试

func testStringLastIndexOf() {
    let lastIndex = "google.com/program/test".lastIndexOf("/")

    XCTAssertEqual(lastIndex, 18)
}

func testStringLastIndexOfNotFound() {
    let lastIndex = "google.com".lastIndexOf("/")

    XCTAssertEqual(lastIndex, nil);
}

【讨论】:

    【解决方案4】:

    @nhgrif 可能是正确的,这是一个 XY 问题,您真正想要做的是解析路径或 URL,并且 NSString 和 NSURL 中有内置方法可以为您完成。

    如果您正在谈论通用字符串解析,也有一些方法可以解决这个问题。

    到目前为止,最简单的做法是使用 NSString 方法rangeOfString:options: 选项值之一是 BackwardsSearch。因此,您将向其传递 BackwardsSearch 的选项值。您将获得搜索字符串最后次出现的范围。

    我见过一些使用“Swift 化”版本范围的 Swift 字符串方法,但不清楚哪些 NSString 方法具有原生 Swift 变体。 (我自己也在学习 Swift。)

    【讨论】:

      【解决方案5】:

      以下内容使用一个扩展来完成此任务,该扩展可以使用您选择的字符串进行定位。如果它不可用,那么你会得到一个你可以处理的 nil 值。

      extension String {
          func lastOccurrenceOfString(string: String) -> String.Index? {
              let characterSet = CharacterSet(charactersIn: string)
              if let range = rangeOfCharacter(from: characterSet, options: .backwards) {
                  let offsetBy = distance(from: startIndex, to: range.upperBound)
      
                  return index(startIndex, offsetBy: offsetBy)
              }
      
              return nil
          }
      }
      

      以下显示了它的使用情况:

      import UIKit
      
      class ViewController: UIViewController {
          let testString = "google.com/program/test"
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
              getIndex(of: "/") // 19
              getIndex(of: ".") // 7
              getIndex(of: "z") // N/A
              getIndex(of: "me") // 21, e appears before m
          }
      
          func getIndex(of string: String) {
      
              let slashIndex = testString.lastOccurrenceOfString(string: string)
              print(slashIndex?.encodedOffset ?? "N/A")
          }
      }
      
      extension String {
          func lastOccurrenceOfString(string: String) -> String.Index? {
              let characterSet = CharacterSet(charactersIn: string)
              if let range = rangeOfCharacter(from: characterSet, options: .backwards) {
                  let offsetBy = distance(from: startIndex, to: range.upperBound)
      
                  return index(startIndex, offsetBy: offsetBy)
              }
      
              return nil
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-10-31
        • 2012-03-23
        • 2011-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-08
        • 2021-01-10
        相关资源
        最近更新 更多