Swift: How to get substring from start to last index of character

前端 未结 22 800
感情败类
感情败类 2020-11-30 19:09

I want to learn the best/simplest way to turn a string into another string but with only a subset, starting at the beginning and going to the last index of a character.

22条回答
  •  [愿得一人]
    2020-11-30 19:44

    Swift 3, XCode 8

    func lastIndexOfCharacter(_ c: Character) -> Int? {
        return range(of: String(c), options: .backwards)?.lowerBound.encodedOffset
    }
    

    Since advancedBy(Int) is gone since Swift 3 use String's method index(String.Index, Int). Check out this String extension with substring and friends:

    public extension String {
    
        //right is the first encountered string after left
        func between(_ left: String, _ right: String) -> String? {
            guard let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
            , leftRange.upperBound <= rightRange.lowerBound
                else { return nil }
    
            let sub = self.substring(from: leftRange.upperBound)
            let closestToLeftRange = sub.range(of: right)!
            return sub.substring(to: closestToLeftRange.lowerBound)
        }
    
        var length: Int {
            get {
                return self.characters.count
            }
        }
    
        func substring(to : Int) -> String {
            let toIndex = self.index(self.startIndex, offsetBy: to)
            return self.substring(to: toIndex)
        }
    
        func substring(from : Int) -> String {
            let fromIndex = self.index(self.startIndex, offsetBy: from)
            return self.substring(from: fromIndex)
        }
    
        func substring(_ r: Range) -> String {
            let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
            let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
            return self.substring(with: Range(uncheckedBounds: (lower: fromIndex, upper: toIndex)))
        }
    
        func character(_ at: Int) -> Character {
            return self[self.index(self.startIndex, offsetBy: at)]
        }
    
        func lastIndexOfCharacter(_ c: Character) -> Int? {
            guard let index = range(of: String(c), options: .backwards)?.lowerBound else
            { return nil }
            return distance(from: startIndex, to: index)
        }
    }
    

    UPDATED extension for Swift 4

    public extension String {
    
        //right is the first encountered string after left
        func between(_ left: String, _ right: String) -> String? {
            guard
                let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards)
                , leftRange.upperBound <= rightRange.lowerBound
                else { return nil }
    
            let sub = self[leftRange.upperBound...]
            let closestToLeftRange = sub.range(of: right)!            
            return String(sub[.. String {
            let toIndex = self.index(self.startIndex, offsetBy: to)
            return String(self[...toIndex])
        }
    
        func substring(from : Int) -> String {
            let fromIndex = self.index(self.startIndex, offsetBy: from)
            return String(self[fromIndex...])
        }
    
        func substring(_ r: Range) -> String {
            let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
            let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
            let indexRange = Range(uncheckedBounds: (lower: fromIndex, upper: toIndex))
            return String(self[indexRange])
        }
    
        func character(_ at: Int) -> Character {
            return self[self.index(self.startIndex, offsetBy: at)]
        }
    
        func lastIndexOfCharacter(_ c: Character) -> Int? {
            guard let index = range(of: String(c), options: .backwards)?.lowerBound else
            { return nil }
            return distance(from: startIndex, to: index)
        }
    }
    

    Usage:

    let text = "www.stackoverflow.com"
    let at = text.character(3) // .
    let range = text.substring(0..<3) // www
    let from = text.substring(from: 4) // stackoverflow.com
    let to = text.substring(to: 16) // www.stackoverflow
    let between = text.between(".", ".") // stackoverflow
    let substringToLastIndexOfChar = text.lastIndexOfCharacter(".") // 17
    

    P.S. It's really odd that developers forced to deal with String.Index instead of plain Int. Why should we bother about internal String mechanics and not just have simple substring() methods?

提交回复
热议问题