在String中查找最后一次出现的字符?

时间:2015-04-26 23:10:46

标签: ios string swift

我想找到String中最后一个字符出现的索引。例如,如果我的字符串是"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'的最后一个索引发生在。

5 个答案:

答案 0 :(得分:6)

我没有回答标题中的问题,而是看看你的示例代码并假设这是一个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 documentationNSString有一整套方法称为“使用路径”

答案 1 :(得分:2)

如果你想找到第一个出现的字符,可以使用find函数,所以一个选项就是编写一个反向查找等价物,以常规查找为模型,然后使用:< / p>

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]

答案 2 :(得分:2)

@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);
}

答案 3 :(得分:0)

@nhgrif可能是正确的,这是一个XY问题,你真正想做的是解析一个路径或一个URL,NSString和NSURL中有内置的方法来为你做这个。

如果您正在谈论通用字符串解析,那么也有方法。

到目前为止,最简单的方法是使用NSString方法rangeOfString:options:其中一个选项值是BackwardsSearch。所以你要传递一个BackwardsSearch的选项值。您将获得搜索字符串最后出现的范围。

我见过一些使用“Swift-ified”版本范围的Swift字符串方法,并且我不清楚NSString方法有什么原生Swift变种。 (我自己也在学习Swift。)

答案 4 :(得分:0)

以下使用您可以选择查找的字符串的扩展程序来完成此任务。如果它不可用,那么你可以得到一个可以处理的零值。

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