Swift: Cómo obtener la subcadena desde el principio hasta el último índice de carácter

110

Quiero aprender la forma mejor / más sencilla de convertir una cadena en otra cadena pero con solo un subconjunto, comenzando por el principio y yendo al último índice de un carácter.

Por ejemplo, convierta "www.stackoverflow.com" en "www.stackoverflow". ¿Qué fragmento de código haría eso y sería el más rápido? (Espero que esto no genere un debate, pero no puedo encontrar una buena lección sobre cómo manejar las subcadenas en Swift.

Jason Hocker
fuente

Respuestas:

202

Solo accediendo hacia atrás

La mejor forma es utilizarlo substringToIndexcombinado con la endIndexpropiedad y la advancefunción global.

var string1 = "www.stackoverflow.com"

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

var substring1 = string1.substringToIndex(index1)

Buscando una cuerda empezando por la espalda

Usar rangeOfStringy configurar optionsen.BackwardsSearch

var string2 = "www.stackoverflow.com"

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

var substring2 = string2.substringToIndex(index2!)

Sin extensiones, Swift puramente idiomático

Swift 2.0

advanceahora es parte de Indexy se llama advancedBy. Lo haces como:

var string1 = "www.stackoverflow.com"

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

var substring1 = string1.substringToIndex(index1)

Swift 3.0

No puede llamar advancedBya Stringporque tiene elementos de tamaño variable. Tienes que usar index(_, offsetBy:).

var string1 = "www.stackoverflow.com"

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

var substring1 = string1.substring(to: index1)

Se ha cambiado el nombre de muchas cosas. Los casos están escritos en camelCase, se startIndexconvirtió lowerBound.

var string2 = "www.stackoverflow.com"

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

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

Además, no recomendaría desenvolver a la fuerza index2. Puede utilizar enlace opcional o map. Personalmente, prefiero usar map:

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

Rápido 4

La versión Swift 3 sigue siendo válida, pero ahora puede usar subíndices con rangos de índices:

let string1 = "www.stackoverflow.com"

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

let substring1 = string1[..<index1]

El segundo enfoque permanece sin cambios:

let string2 = "www.stackoverflow.com"

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

let substring3 = index2.map(string2.substring(to:))
fpg1503
fuente
1
Gracias @ fpg1503. Este es el tipo de respuesta que buscaba encontrar. Las otras respuestas me enseñaron o me recordaron las características del idioma, pero esta es la forma que utilizaré para resolver mi problema.
Jason Hocker
1
Usar Swift 2.0 string1.endIndex.advancedBy(-4)me está funcionando en lugar deadvance
Alex Koshy
92
¿En serio, no hay forma de hacer esto simplemente?
devios1
12
@devios todo es cierto. Estoy agradecido por Swift en comparación con Objective-C, pero en mi humilde opinión, las preocupaciones que conducen a este código increíblemente incómodo son irrelevantes para el 99% del código y los codificadores que existen. Peor aún, terminaremos escribiendo malas extensiones de conveniencia nosotros mismos. Si los desarrolladores habituales no pueden comprender estas preocupaciones de alto nivel, son los MENOS capaces de escribir una API ad-hoc para hacer frente a las preocupaciones de los peatones con las que creamos software. La tendencia a convertirse a NSStringes obviamente mala también, porque eventualmente todos queremos alejarnos de las clases de la Fundación (legado). Entonces ... ¡más despotricar!
Dan Rosenstark
2
En Swift 4, puedes hacerlo string1[..<index1]. No es necesario string1.startIndex.
bauerMusic
26

Swift 3, XCode 8

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

Dado que advancedBy(Int)se ha ido desde Stringel método de uso de Swift 3 index(String.Index, Int). Mira esta Stringextensión con subcadena y 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)
    }
}

Extensión ACTUALIZADA 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

PD: Es realmente extraño que los desarrolladores se vean obligados a tratar en String.Indexlugar de hacerlo simple Int. ¿Por qué deberíamos preocuparnos por la Stringmecánica interna y no solo tener substring()métodos simples ?

serg_zhd
fuente
No debe usar encodedOffsetverificar este comentario y la forma correcta de lograrlo stackoverflow.com/questions/34540185/…
Leo Dabus
18

Lo haría usando un subíndice ( s[start..<end]):

Rápido 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ý
fuente
11

editar / actualizar:

En Swift 4 o posterior (Xcode 10.0+) puede usar el nuevo 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
fuente
Esta es una gran respuesta, pero parece que con Swift 2, esta propiedad se ha movido a NSUrl. Tal vez esto ayude a la gente que lee esto en el futuro ...
chuky
8

Así es como lo hago. Puede hacerlo de la misma manera o usar este código para obtener ideas.

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

Aquí están las extensiones 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 / Extensiones de cadenas Swift comunes

Generalmente soy un firme defensor de las extensiones, especialmente para necesidades como manipulación, búsqueda y corte de cadenas.

joelparkerhenderson
fuente
2
Creo que esto es realmente algo que Apple debería hacer para mejorar la API de String en Swift.
skyline75489
2
Buscando esta API. Apple Swift carece de muchas API básicas. Es un lenguaje muy complejo y tampoco completo. ¡Swift es una mierda!
Loc
Aquí hay una versión bifurcada y actualizada a Swift 3 de la biblioteca a la que hace referencia: github.com/iamjono/SwiftString
RenniePet
5

String tiene una función de subcadena incorporada:

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

Si lo que desea es "ir al primer índice de un carácter", puede obtener la subcadena usando la find()función incorporada :

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

Para encontrar el ú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`

ADICIONAL:

Quizás, la BidirectionalIndexTypeversión especializada de findLastes más 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
fuente
El subíndice de String no parece estar disponible en Swift 2.0, ¿conoce un reemplazo?
Cory
¿Sabe cómo puedo restringir Index a BidirectionalIndexType en Swift 4 o posterior?
Leo Dabus
5

Puedes usar estas extensiones:

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
fuente
5

Rápido 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)
        }
    }
}

puedes probarlo de la siguiente manera:

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

Consulte la biblioteca https://gitlab.com/seriyvolk83/SwiftEx . Contiene estos y otros métodos útiles.

Alexander Volkov
fuente
4

¿Desea obtener una subcadena de una cadena desde el índice de inicio hasta el último índice de uno de sus caracteres? Si es así, puede elegir uno de los siguientes métodos Swift 2.0+.

Métodos que requieren Foundation

Obtenga una subcadena que incluya el último índice de un carácter:

import Foundation

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

// prints "www.stackoverflow."

Obtenga una subcadena que NO incluya el último índice de un carácter:

import Foundation

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

// prints "www.stackoverflow"

Si necesita repetir esas operaciones, extender Stringpuede ser una buena solución:

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 NO requieren Foundation

Obtenga una subcadena que incluya el último índice de un carácter:

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

// prints "www.stackoverflow."

Obtenga una subcadena que NO incluya el último índice de un carácter:

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

// prints "www.stackoverflow"

Si necesita repetir esas operaciones, extender Stringpuede ser una buena solución:

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
fuente
4

A continuación, se muestra una forma fácil y breve de obtener una subcadena si conoce el índice:

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

No bloqueará la aplicación si su índice excede la longitud de la cadena:

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

Ambos ejemplos están listos para Swift 3 .

Andrey Gordeev
fuente
4

Lo único que agrega ruido es lo repetido stringVar:

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

En Swift 4

Una extensión puede reducir algo de eso:

extension String {

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

Entonces, uso:

let string = "abcde"

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

Cabe señalar que toy fromson de tipo Substring(o String.SubSequance). No asignan nuevas cadenas y son más eficientes para el procesamiento.

Para recuperar un Stringtipo, es Substringnecesario volver a convertirlo en String:

let backToString = String(from)

Aquí es donde finalmente se asigna una cadena.

bauerMusic
fuente
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)
Profesor Oak
fuente
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

Buen artículo para entender, ¿por qué necesitamos esto?

Nik Kov
fuente
2

He extendido String con dos métodos de subcadena. Puede llamar a la subcadena con un rango desde / hasta o desde / longitud así:

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
fuente
self.length ya no está disponible. Debe agregar esto en la extensión (Andrewz, actualice el código; no quiero publicar otra respuesta): public func length () -> Int {return self.lengthOfBytesUsingEncoding (NSUTF16StringEncoding)}
philippe
1

Swift 2.0 El siguiente código se prueba en XCode 7.2. Consulte la captura de pantalla adjunta en la 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
fuente
1

En Swift 5

Necesitamos en String.Indexlugar de un valor Int simple para representar Index.

También recuerde, cuando intentamos obtener subString de Swift String(tipo de valor), en realidad tenemos que iterar con el Sequenceprotocolo, que devuelve String.SubSequencetipo en lugar de Stringtipo.

Para volver Stringde String.SubSequence, useString(subString)

Ejemplo de la siguiente manera:

    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
fuente
0

Para Swift 2.0 , es así:

var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)
mike.tihonchik
fuente
Tal vez lo hayan cambiado, pero es 'advancedBy' (observe la 'd' al final de 'advanced')
Wedge Martin
0

Modifiqué la publicación de andrewz para que sea compatible con Swift 2.0 (y tal vez Swift 3.0). En mi humilde opinión, esta extensión es más fácil de entender y similar a lo que está disponible en otros lenguajes (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)))
    }
}
philippe
fuente
0

También creo una extensión de cadena simple 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])
     }
}

Entonces puedes llamarlo fácilmente así:

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

Pruebe esta Int-basedsolución 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: es solo una práctica. No comprueba el límite. Modifique para satisfacer sus necesidades.

steveluoxin
fuente
-1

Aquí hay una forma sencilla de obtener subcadenas en Swift

import UIKit

var str = "Hello, playground" 
var res = NSString(string: str)
print(res.substring(from: 4))
print(res.substring(to: 10))
ZagorTeNej
fuente
OP pregunta "Cómo obtener una subcadena desde el inicio hasta el último índice de carácter", no cómo obtener una subcadena usando valores predefinidos codificados.
Eric Aya
Este fue un ejemplo original: convertir "www.stackoverflow.com" a "www.stackoverflow". Si desea una subcadena desde el principio hasta el final, entonces no hay nada que hacer, es decir, el resultado es la cadena de entrada como está. Restaure la utilidad de la respuesta anterior.
ZagorTeNej