Swift: como obter substring do início ao último índice de caractere

110

Eu quero aprender a maneira melhor / mais simples de transformar uma string em outra string, mas com apenas um subconjunto, começando no início e indo até o último índice de um caractere.

Por exemplo, converta "www.stackoverflow.com" em "www.stackoverflow". Que trecho de código faria isso, e sendo o mais rápido? (Espero que isso não traga um debate, mas não consigo encontrar uma boa lição sobre como lidar com substrings em Swift.

Jason Hocker
fonte

Respostas:

202

Apenas acessando para trás

A melhor maneira é usar substringToIndexcombinado com a endIndexpropriedade e a advancefunção global.

var string1 = "www.stackoverflow.com"

var index1 = advance(string1.endIndex, -4)

var substring1 = string1.substringToIndex(index1)

Procurando um barbante começando pelas costas

Use rangeOfStringe defina optionspara.BackwardsSearch

var string2 = "www.stackoverflow.com"

var index2 = string2.rangeOfString(".", options: .BackwardsSearch)?.startIndex

var substring2 = string2.substringToIndex(index2!)

Sem extensões, Swift idiomático puro

Swift 2.0

advanceagora faz parte de Indexe é chamado advancedBy. Você faz como:

var string1 = "www.stackoverflow.com"

var index1 = string1.endIndex.advancedBy(-4)

var substring1 = string1.substringToIndex(index1)

Swift 3.0

Você não pode chamar advancedByum Stringporque tem elementos de tamanho variável. Você tem que usar index(_, offsetBy:).

var string1 = "www.stackoverflow.com"

var index1 = string1.index(string1.endIndex, offsetBy: -4)

var substring1 = string1.substring(to: index1)

Muitas coisas foram renomeadas. Os casos são escritos em camelCase, startIndextornou-se lowerBound.

var string2 = "www.stackoverflow.com"

var index2 = string2.range(of: ".", options: .backwards)?.lowerBound

var substring2 = string2.substring(to: index2!)

Além disso, eu não recomendaria o desembrulhamento forçado index2. Você pode usar ligação opcional ou map. Pessoalmente, prefiro usar map:

var substring3 = index2.map(string2.substring(to:))

Swift 4

A versão do Swift 3 ainda é válida, mas agora você pode usar subscritos com intervalos de índices:

let string1 = "www.stackoverflow.com"

let index1 = string1.index(string1.endIndex, offsetBy: -4)

let substring1 = string1[..<index1]

A segunda abordagem permanece inalterada:

let string2 = "www.stackoverflow.com"

let index2 = string2.range(of: ".", options: .backwards)?.lowerBound

let substring3 = index2.map(string2.substring(to:))
fpg1503
fonte
1
Obrigado @ fpg1503. Esse é o tipo de resposta que eu procurava encontrar. As outras respostas me ensinaram ou me lembraram recursos da linguagem, mas é assim que vou usar para resolver meu problema.
Jason Hocker
1
Usar o Swift 2.0 string1.endIndex.advancedBy(-4)está funcionando para mim em vez deadvance
Alex Koshy,
92
Sério, não há maneira de fazer isso simplesmente?
devios1
12
@devios all true. Sou grato por Swift em comparação com Objective-C, mas IMHO as preocupações que levam a este código insanamente estranho são irrelevantes para 99% do código e codificadores por aí. Pior, acabaremos escrevendo extensões de conveniência inadequadas. Se os desenvolvedores regulares não conseguem entender essas preocupações de nível superior, eles são o MENOS capazes de escrever uma API ad-hoc para lidar com as preocupações pedestres com as quais fazemos software. A tendência de conversão também NSStringé obviamente ruim, porque eventualmente todos nós queremos nos afastar das classes Foundation (legado). Então .... mais reclamação!
Dan Rosenstark
2
No Swift 4, você pode fazer string1[..<index1]. Não há necessidade string1.startIndex.
bauerMusic de
26

Swift 3, XCode 8

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

Desde que advancedBy(Int)se foi desde Stringo método de uso do Swift 3 index(String.Index, Int). Confira esta Stringextensão com substring e amigos:

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<Int>) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        return self.substring(with: Range<String.Index>(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)
    }
}

Extensão ATUALIZADA para 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[..<closestToLeftRange.lowerBound])
    }

    var length: Int {
        get {
            return self.count
        }
    }

    func substring(to : Int) -> 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<Int>) -> String {
        let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        let indexRange = Range<String.Index>(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)
    }
}

Uso:

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

PS É realmente estranho que os desenvolvedores sejam forçados a lidar em String.Indexvez de simples Int. Por que devemos nos preocupar com a Stringmecânica interna e não apenas ter substring()métodos simples ?

serg_zhd
fonte
Você não deve encodedOffsetverificar este comentário e a maneira correta de realizar esse stackoverflow.com/questions/34540185/…
Leo Dabus
18

Eu faria isso usando um subscrito ( s[start..<end]):

Swift 3, 4, 5

let s = "www.stackoverflow.com"
let start = s.startIndex
let end = s.index(s.endIndex, offsetBy: -4)
let substring = s[start..<end] // www.stackoverflow
Marián Černý
fonte
11

editar / atualizar:

No Swift 4 ou posterior (Xcode 10.0+), você pode usar o novo método BidirectionalCollection lastIndex (of :)

func lastIndex(of element: Element) -> Int?

let string = "www.stackoverflow.com"
if let lastIndex = string.lastIndex(of: ".") {
    let subString = string[..<lastIndex]  // "www.stackoverflow"
}
Leo Dabus
fonte
Esta é uma ótima resposta, mas parece que com o Swift 2, esta propriedade foi movida para NSUrl. Talvez isso ajude as pessoas a ler isso no futuro ...
chuky
8

É assim que eu faço. Você pode fazer isso da mesma maneira ou usar este código para ter ideias.

let s = "www.stackoverflow.com"
s.substringWithRange(0..<s.lastIndexOf("."))

Aqui estão as extensões que uso:

import Foundation
extension String {

  var length: Int {
    get {
      return countElements(self)
    }
  }

  func indexOf(target: String) -> Int {
    var range = self.rangeOfString(target)
    if let range = range {
      return distance(self.startIndex, range.startIndex)
    } else {
      return -1
    }
  }

  func indexOf(target: String, startIndex: Int) -> Int {
    var startRange = advance(self.startIndex, startIndex)        
    var range = self.rangeOfString(target, options: NSStringCompareOptions.LiteralSearch, range: Range<String.Index>(start: startRange, end: self.endIndex))
    if let range = range {
      return distance(self.startIndex, range.startIndex)
    } else {
      return -1
    }
  }

  func lastIndexOf(target: String) -> Int {
    var index = -1
    var stepIndex = self.indexOf(target)
    while stepIndex > -1 {
      index = stepIndex
      if stepIndex + target.length < self.length {
        stepIndex = indexOf(target, startIndex: stepIndex + target.length)
      } else {
        stepIndex = -1
      }
    }
    return index
  } 

  func substringWithRange(range:Range<Int>) -> String {
    let start = advance(self.startIndex, range.startIndex)
    let end = advance(self.startIndex, range.endIndex)
    return self.substringWithRange(start..<end)
  }

}

Crédito albertbori / Extensões de String Swift Comum

Geralmente, eu sou um forte defensor das extensões, especialmente para necessidades como manipulação de cordas, pesquisa e corte.

joelparkerhenderson
fonte
2
Eu acho que isso é realmente algo que a Apple deveria fazer, para melhorar a API de String no Swift.
skyline75489
2
Procurando por esta API. O Apple Swift carece de muitas APIs básicas. É uma linguagem muito complexa e também incompleta. Swift é uma besteira!
Loc.
Aqui está uma versão bifurcada e atualizada para a versão Swift 3 da biblioteca à qual você faz referência: github.com/iamjono/SwiftString
RenniePet
5

String tem recurso de substring embutido:

extension String : Sliceable {
    subscript (subRange: Range<String.Index>) -> String { get }
}

Se o que você deseja é "ir para o primeiro índice de um caractere", você pode obter a substring usando a find()função embutida:

var str = "www.stackexchange.com"
str[str.startIndex ..< find(str, ".")!] // -> "www"

Para encontrar o último índice, podemos implementar findLast().

/// Returns the last index where `value` appears in `domain` or `nil` if
/// `value` is not found.
///
/// Complexity: O(\ `countElements(domain)`\ )
func findLast<C: CollectionType where C.Generator.Element: Equatable>(domain: C, value: C.Generator.Element) -> C.Index? {
    var last:C.Index? = nil
    for i in domain.startIndex..<domain.endIndex {
        if domain[i] == value {
            last = i
        }
    }
    return last
}

let str = "www.stackexchange.com"
let substring = map(findLast(str, ".")) { str[str.startIndex ..< $0] } // as String?
// if "." is found, substring has some, otherwise `nil`

ADICIONADO:

Talvez a BidirectionalIndexTypeversão especializada do findLastseja mais rápida:

func findLast<C: CollectionType where C.Generator.Element: Equatable, C.Index: BidirectionalIndexType>(domain: C, value: C.Generator.Element) -> C.Index? {
    for i in lazy(domain.startIndex ..< domain.endIndex).reverse() {
        if domain[i] == value {
            return i
        }
    }
    return nil
}
Rintaro
fonte
O subscrito para String não parece estar disponível no Swift 2.0, você conhece um substituto?
Cory
Você sabe como posso restringir Index para BidirectionalIndexType no Swift 4 ou posterior?
Leo Dabus
5

Você pode usar estas extensões:

Swift 2.3

 extension String
    {
        func substringFromIndex(index: Int) -> String
        {
            if (index < 0 || index > self.characters.count)
            {
                print("index \(index) out of bounds")
                return ""
            }
            return self.substringFromIndex(self.startIndex.advancedBy(index))
        }

        func substringToIndex(index: Int) -> String
        {
            if (index < 0 || index > self.characters.count)
            {
                print("index \(index) out of bounds")
                return ""
            }
            return self.substringToIndex(self.startIndex.advancedBy(index))
        }

        func substringWithRange(start: Int, end: Int) -> String
        {
            if (start < 0 || start > self.characters.count)
            {
                print("start index \(start) out of bounds")
                return ""
            }
            else if end < 0 || end > self.characters.count
            {
                print("end index \(end) out of bounds")
                return ""
            }
            let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
            return self.substringWithRange(range)
        }

        func substringWithRange(start: Int, location: Int) -> String
        {
            if (start < 0 || start > self.characters.count)
            {
                print("start index \(start) out of bounds")
                return ""
            }
            else if location < 0 || start + location > self.characters.count
            {
                print("end index \(start + location) out of bounds")
                return ""
            }
            let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
            return self.substringWithRange(range)
        }
    }

Swift 3

extension String
{   
    func substring(from index: Int) -> String
    {
        if (index < 0 || index > self.characters.count)
        {
            print("index \(index) out of bounds")
            return ""
        }
        return self.substring(from: self.characters.index(self.startIndex, offsetBy: index))
    }

    func substring(to index: Int) -> String
    {
        if (index < 0 || index > self.characters.count)
        {
            print("index \(index) out of bounds")
            return ""
        }
        return self.substring(to: self.characters.index(self.startIndex, offsetBy: index))
    }

    func substring(start: Int, end: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if end < 0 || end > self.characters.count
        {
            print("end index \(end) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: end)
        let range = startIndex..<endIndex

        return self.substring(with: range)
    }

    func substring(start: Int, location: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if location < 0 || start + location > self.characters.count
        {
            print("end index \(start + location) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
        let range = startIndex..<endIndex

        return self.substring(with: range)
    }
}

Uso:

let string = "www.stackoverflow.com"        
let substring = string.substringToIndex(string.characters.count-4)
ChikabuZ
fonte
5

Swift 4:

extension String {

    /// the length of the string
    var length: Int {
        return self.characters.count
    }

    /// Get substring, e.g. "ABCDE".substring(index: 2, length: 3) -> "CDE"
    ///
    /// - parameter index:  the start index
    /// - parameter length: the length of the substring
    ///
    /// - returns: the substring
    public func substring(index: Int, length: Int) -> String {
        if self.length <= index {
            return ""
        }
        let leftIndex = self.index(self.startIndex, offsetBy: index)
        if self.length <= index + length {
            return self.substring(from: leftIndex)
        }
        let rightIndex = self.index(self.endIndex, offsetBy: -(self.length - index - length))
        return self.substring(with: leftIndex..<rightIndex)
    }

    /// Get substring, e.g. -> "ABCDE".substring(left: 0, right: 2) -> "ABC"
    ///
    /// - parameter left:  the start index
    /// - parameter right: the end index
    ///
    /// - returns: the substring
    public func substring(left: Int, right: Int) -> String {
        if length <= left {
            return ""
        }
        let leftIndex = self.index(self.startIndex, offsetBy: left)
        if length <= right {
            return self.substring(from: leftIndex)
        }
        else {
            let rightIndex = self.index(self.endIndex, offsetBy: -self.length + right + 1)
            return self.substring(with: leftIndex..<rightIndex)
        }
    }
}

você pode testá-lo da seguinte maneira:

    print("test: " + String("ABCDE".substring(index: 2, length: 3) == "CDE"))
    print("test: " + String("ABCDE".substring(index: 0, length: 3) == "ABC"))
    print("test: " + String("ABCDE".substring(index: 2, length: 1000) == "CDE"))
    print("test: " + String("ABCDE".substring(left: 0, right: 2) == "ABC"))
    print("test: " + String("ABCDE".substring(left: 1, right: 3) == "BCD"))
    print("test: " + String("ABCDE".substring(left: 3, right: 1000) == "DE"))

Verifique a biblioteca https://gitlab.com/seriyvolk83/SwiftEx . Ele contém esses e outros métodos úteis.

Alexander Volkov
fonte
4

Você deseja obter uma substring de uma string do índice inicial até o último índice de um de seus caracteres? Nesse caso, você pode escolher um dos seguintes métodos do Swift 2.0+.

Métodos que requerem Foundation

Obtenha uma substring que inclua o último índice de um caractere:

import Foundation

let string = "www.stackoverflow.com"
if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) {
    print(string.substringToIndex(rangeOfIndex.endIndex))
}

// prints "www.stackoverflow."

Obtenha uma substring que NÃO inclua o último índice de um caractere:

import Foundation

let string = "www.stackoverflow.com"
if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) {
    print(string.substringToIndex(rangeOfIndex.startIndex))
}

// prints "www.stackoverflow"

Se você precisar repetir essas operações, a extensão Stringpode ser uma boa solução:

import Foundation

extension String {
    func substringWithLastInstanceOf(character: Character) -> String? {
        if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) {
            return self.substringToIndex(rangeOfIndex.endIndex)
        }
        return nil
    }
    func substringWithoutLastInstanceOf(character: Character) -> String? {
        if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) {
            return self.substringToIndex(rangeOfIndex.startIndex)
        }
        return nil
    }
}

print("www.stackoverflow.com".substringWithLastInstanceOf("."))
print("www.stackoverflow.com".substringWithoutLastInstanceOf("."))

/*
prints:
Optional("www.stackoverflow.")
Optional("www.stackoverflow")
*/

Métodos que NÃO requerem Foundation

Obtenha uma substring que inclua o último índice de um caractere:

let string = "www.stackoverflow.com"
if let reverseIndex = string.characters.reverse().indexOf(".") {
    print(string[string.startIndex ..< reverseIndex.base])
}

// prints "www.stackoverflow."

Obtenha uma substring que NÃO inclua o último índice de um caractere:

let string = "www.stackoverflow.com"
if let reverseIndex = string.characters.reverse().indexOf(".") {
    print(string[string.startIndex ..< reverseIndex.base.advancedBy(-1)])
}

// prints "www.stackoverflow"

Se você precisar repetir essas operações, a extensão Stringpode ser uma boa solução:

extension String {
    func substringWithLastInstanceOf(character: Character) -> String? {
        if let reverseIndex = characters.reverse().indexOf(".") {
            return self[self.startIndex ..< reverseIndex.base]
        }
        return nil
    }
    func substringWithoutLastInstanceOf(character: Character) -> String? {
        if let reverseIndex = characters.reverse().indexOf(".") {
            return self[self.startIndex ..< reverseIndex.base.advancedBy(-1)]
        }
        return nil
    }
}

print("www.stackoverflow.com".substringWithLastInstanceOf("."))
print("www.stackoverflow.com".substringWithoutLastInstanceOf("."))

/*
prints:
Optional("www.stackoverflow.")
Optional("www.stackoverflow")
*/
Imanou Petit
fonte
4

Esta é uma maneira fácil e curta de obter uma substring se você souber o índice:

let s = "www.stackoverflow.com"
let result = String(s.characters.prefix(17)) // "www.stackoverflow"

O aplicativo não travará se o índice exceder o comprimento da string:

let s = "short"
let result = String(s.characters.prefix(17)) // "short"

Ambos os exemplos estão prontos para Swift 3 .

Andrey Gordeev
fonte
4

A única coisa que adiciona barulho é a repetição stringVar:

stringVar [ stringVar .index ( stringVar .startIndex, offsetBy: ...)

Em Swift 4

Uma extensão pode reduzir isso:

extension String {

    func index(at: Int) -> String.Index {
        return self.index(self.startIndex, offsetBy: at)
    }
}

Então, uso:

let string = "abcde"

let to = string[..<string.index(at: 3)] // abc
let from = string[string.index(at: 3)...] // de

Deve-se notar que toe fromsão tipo Substring(ou String.SubSequance). Eles não alocam novas strings e são mais eficientes para processamento.

Para recuperar um Stringtipo, Substringprecisa ser convertido de volta para String:

let backToString = String(from)

É aqui que uma string é finalmente alocada.

bauerMusic
fonte
3
func substr(myString: String, start: Int, clen: Int)->String

{
  var index2 = string1.startIndex.advancedBy(start)
  var substring2 = string1.substringFromIndex(index2)
  var index1 = substring2.startIndex.advancedBy(clen)
  var substring1 = substring2.substringToIndex(index1)

  return substring1   
}

substr(string1, start: 3, clen: 5)
Professor carvalho
fonte
3

Swift 3

let string = "www.stackoverflow.com"
let first3Characters = String(string.characters.prefix(3)) // www
let lastCharacters = string.characters.dropFirst(4) // stackoverflow.com (it would be a collection)

//or by index 
let indexOfFouthCharacter = olNumber.index(olNumber.startIndex, offsetBy: 4)
let first3Characters = olNumber.substring(to: indexOfFouthCharacter) // www
let lastCharacters = olNumber.substring(from: indexOfFouthCharacter) // .stackoverflow.com

Bom artigo para compreensão, por que precisamos disso

Nik Kov
fonte
2

Estendi String com dois métodos de substring. Você pode chamar substring com um intervalo de / para ou de / comprimento como:

var bcd = "abcdef".substring(1,to:3)
var cde = "abcdef".substring(2,to:-2)
var cde = "abcdef".substring(2,length:3)

extension String {
  public func substring(from:Int = 0, var to:Int = -1) -> String {
    if to < 0 {
        to = self.length + to
    }
    return self.substringWithRange(Range<String.Index>(
        start:self.startIndex.advancedBy(from),
        end:self.startIndex.advancedBy(to+1)))
  }
  public func substring(from:Int = 0, length:Int) -> String {
    return self.substringWithRange(Range<String.Index>(
        start:self.startIndex.advancedBy(from),
        end:self.startIndex.advancedBy(from+length)))
  }
}
andrewz
fonte
self.length não está mais disponível. Você precisa adicionar isso na extensão (Andrewz, atualize o código; não quero postar outra resposta): public func length () -> Int {return self.lengthOfBytesUsingEncoding (NSUTF16StringEncoding)}
philippe
1

Swift 2.0 O código abaixo foi testado no XCode 7.2. Por favor, consulte a imagem em anexo na parte inferior

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var mainText = "http://stackoverflow.com"

        var range = Range(start: mainText.startIndex.advancedBy(7), end: mainText.startIndex.advancedBy(24))
        var subText = mainText.substringWithRange(range)


        //OR Else use below for LAST INDEX

        range = Range(start: mainText.startIndex.advancedBy(7), end: mainText.endIndex)
        subText = mainText.substringWithRange(range)
    }
}
Chamath Jeevan
fonte
1

Em Swift 5

Precisamos, em String.Indexvez do valor Int simples, para representar o Índice.

Lembre-se também, quando tentamos obter subString de Swift String(tipo de valor), na verdade temos que iterar com Sequenceprotocolo, que retorna String.SubSequencetipo em vez de Stringtipo.

Para voltar Stringde String.SubSequence, useString(subString)

Exemplo como abaixo:

    let string = "https://stackoverflow.com"
    let firstIndex = String.Index(utf16Offset: 0, in: string)
    let lastIndex = String.Index(utf16Offset: 6, in: string)
    let subString = String(string[firstIndex...lastIndex])
macpandit
fonte
0

Para Swift 2.0 , é assim:

var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)
mike.tihonchik
fonte
Talvez eles tenham mudado, mas é 'advancedBy' (observe o 'd' no final de 'avançado')
Wedge Martin
0

Modifiquei a postagem de andrewz para torná-la compatível com Swift 2.0 (e talvez Swift 3.0). Na minha humilde opinião, esta extensão é mais fácil de entender e semelhante ao que está disponível em outras linguagens (como PHP).

extension String {

    func length() -> Int {
        return self.lengthOfBytesUsingEncoding(NSUTF16StringEncoding)
    }
    func substring(from:Int = 0, to:Int = -1) -> String {
       var nto=to
        if nto < 0 {
            nto = self.length() + nto
        }
        return self.substringWithRange(Range<String.Index>(
           start:self.startIndex.advancedBy(from),
           end:self.startIndex.advancedBy(nto+1)))
    }
    func substring(from:Int = 0, length:Int) -> String {
        return self.substringWithRange(Range<String.Index>(
            start:self.startIndex.advancedBy(from),
            end:self.startIndex.advancedBy(from+length)))
    }
}
Filipe
fonte
0

Eu também construí uma extensão de string simples para Swift 4:

extension String {
    func subStr(s: Int, l: Int) -> String { //s=start, l=lenth
        let r = Range(NSRange(location: s, length: l))!
        let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let toIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        let indexRange = Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex))

        return String(self[indexRange])
     }
}

Portanto, você pode chamá-lo facilmente assim:

"Hallo world".subStr(s: 1, l: 3) //prints --> "all"
Marco Weber
fonte
0

Tente esta Int-basedsolução alternativa:

extension String {
    // start and end is included
    func intBasedSubstring(_ start: Int, _ end: Int) -> String {
        let endOffset: Int = -(count - end - 1)
        let startIdx = self.index(startIndex, offsetBy: start)
        let endIdx = self.index(endIndex, offsetBy: endOffset)
        return String(self[startIdx..<endIdx])
    }
}

Nota: é apenas uma prática. Não verifica o limite. Modifique para atender às suas necessidades.

esteveluoxina
fonte
-1

Aqui está uma maneira simples de obter substring em Swift

import UIKit

var str = "Hello, playground" 
var res = NSString(string: str)
print(res.substring(from: 4))
print(res.substring(to: 10))
ZagorTeNej
fonte
OP pergunta "Como obter substring do início ao último índice de caractere", não como obter substring usando valores predefinidos codificados.
Eric Aya
Este foi o exemplo original: converta "www.stackoverflow.com" para "www.stackoverflow". Se você quiser uma substring do início ao fim, não há nada a fazer, ou seja, o resultado é a string de entrada como está. Restaure a utilidade da resposta acima.
ZagorTeNej