¿Dividir una cadena en una matriz en Swift?

686

Digamos que tengo una cadena aquí:

var fullName: String = "First Last"

Quiero dividir la base de la cadena en el espacio en blanco y asignar los valores a sus respectivas variables

var fullNameArr = // something like: fullName.explode(" ") 

var firstName: String = fullNameArr[0]
var lastName: String? = fullnameArr[1]

Además, a veces los usuarios pueden no tener un apellido.

blee908
fuente
13
Hola, no tengo que revisar mi Mac. Pero puede probar 'fullName.componentsSeparatedByString (string: "")' No copie y pegue, use la función autocompletar, para obtener la función correcta.
David Gölzhäuser
Si solo está dividiendo por un carácter, el uso también fullName.utf8.split( <utf-8 character code> )funciona (reemplace .utf8con .utf16UTF-16). Por ejemplo, la división +podría hacerse usandofullName.utf8.split(43)
Jojodmo
Además, a veces los apellidos tienen espacios en ellos, como en "Daphne du Maurier" o "Charles de Lint"
Berry

Respuestas:

784

La forma rápida es usar la splitfunción global , así:

var fullName = "First Last"
var fullNameArr = split(fullName) {$0 == " "}
var firstName: String = fullNameArr[0]
var lastName: String? = fullNameArr.count > 1 ? fullNameArr[1] : nil

con Swift 2

En Swift 2, el uso de split se vuelve un poco más complicado debido a la introducción del tipo interno de CharacterView. Esto significa que String ya no adopta los protocolos SequenceType o CollectionType y, en su lugar, debe usar la .characterspropiedad para acceder a una representación de tipo CharacterView de una instancia de String. (Nota: CharacterView adopta los protocolos SequenceType y CollectionType).

let fullName = "First Last"
let fullNameArr = fullName.characters.split{$0 == " "}.map(String.init)
// or simply:
// let fullNameArr = fullName.characters.split{" "}.map(String.init)

fullNameArr[0] // First
fullNameArr[1] // Last 
Ethan
fuente
98
En mis pruebas, componentsSeparatedByString suele ser significativamente más rápido, especialmente cuando se trata de cadenas que requieren dividirse en muchas partes. Pero para el ejemplo enumerado por el OP, cualquiera debería ser suficiente.
Casey Perkins
99
A partir de Xcode 6.2b3, la división se puede usar como split("a:b::c:", {$0 == ":"}, maxSplit: Int.max, allowEmptySlices: false).
Pascal
14
Solo recuerde que todavía necesita usar el componentsSeparatedByString()método anterior si su separador es más largo que un solo carácter. Y tan genial como sería decir let (firstName, lastName) = split(fullName) {$0 == ' '}, eso no funciona, lamentablemente.
NRitH
3
@Kashif, entonces podría usar split("a,b;c,d") {$0 == "," || $0 == ";"}osplit("a,b;c,d") {contains(",;", $0)}
Ethan
44
El código correcto para Xcode 7.0 se deja fullNameArr = fullName.characters.split {$ 0 == ""} .map (String.init). Intenté editar, pero fue rechazado.
skagedal
1015

Simplemente llame al componentsSeparatedByStringmétodo en sufullName

import Foundation

var fullName: String = "First Last"
let fullNameArr = fullName.componentsSeparatedByString(" ")

var firstName: String = fullNameArr[0]
var lastName: String = fullNameArr[1]

Actualización para Swift 3+

import Foundation

let fullName    = "First Last"
let fullNameArr = fullName.components(separatedBy: " ")

let name    = fullNameArr[0]
let surname = fullNameArr[1]
Chen-Tsu Lin
fuente
3
Tenga en cuenta que esto es realmente un subyacente NSString(Swift los intercambia automáticamente al importar Foundation).
Puede
1
Lo que ya no es el caso en Swift 1.2, en el que Apple ya no convierte la cadena de Swift en NSString automáticamente.
elcuco
66
Esta respuesta funciona en Xcode 7 beta 4 y Swift 2.0. Xcode ahora completa automáticamente los métodos de Foundation en objetos Swift String sin conversión de tipos en un NSString, que no es el caso en Xcode 6.4 con Swift 1.2.
Andrew
1
No funcionó en REPL hasta que importé Foundation.
Velizar Hristov
1
Esto funciona exactamente como se esperaba (es decir, fullNameArr es an [String]) en Xcode 7.2.
Jon Cox
185

El método más fácil para hacer esto es mediante el uso de componentsSeparatedBy:

Para Swift 2:

import Foundation
let fullName : String = "First Last";
let fullNameArr : [String] = fullName.componentsSeparatedByString(" ")

// And then to access the individual words:

var firstName : String = fullNameArr[0]
var lastName : String = fullNameArr[1]

Para Swift 3:

import Foundation

let fullName : String = "First Last"
let fullNameArr : [String] = fullName.components(separatedBy: " ")

// And then to access the individual words:

var firstName : String = fullNameArr[0]
var lastName : String = fullNameArr[1]
Wyetro
fuente
¿Está documentado en alguna parte, Maury? ¿Qué sucede si necesito dividirme en algo que no sea un solo personaje?
NRitH
10
@NRitH considere .componentsSeparatedByCharactersInSet(.whitespaceAndNewlineCharacterSet())
rmp251
@Crashalot hay dos funciones: componentsSeparatedByStringycomponentsSeparatedByCharactersInSet
rmp251
131

Swift Dev. 4.0 (24 de mayo de 2017)

Una nueva función spliten Swift 4 ( Beta ).

import Foundation
let sayHello = "Hello Swift 4 2017";
let result = sayHello.split(separator: " ")
print(result)

Salida:

["Hello", "Swift", "4", "2017"]

Acceso a valores:

print(result[0]) // Hello
print(result[1]) // Swift
print(result[2]) // 4
print(result[3]) // 2017

Xcode 8.1 / Swift 3.0.1

Aquí está la forma en que varios delimitadores con matriz.

import Foundation
let mathString: String = "12-37*2/5"
let numbers = mathString.components(separatedBy: ["-", "*", "/"])
print(numbers)

Salida:

["12", "37", "2", "5"]
LugiHaue
fuente
8
Asegúrate de agregar import Foundationa la clase en la que estás usando esto. #SavedYouFiveMinutes
Adrian
44
Atención (Swift 4): si tiene una cadena como let a="a,,b,c"y la usa a.split(separator: ","), obtiene una matriz como ["a", "b", c"]por defecto. Esto se puede cambiar usando el omittingEmptySubsequences: falseque es verdadero por defecto.
OderWat
2
¿Alguna división de varios personajes en Swift 4+?
pkamb
57

Swift 4 o posterior

Si solo necesita formatear correctamente el nombre de una persona, puede usar PersonNameComponentsFormatter .

La clase PersonNameComponentsFormatter proporciona representaciones localizadas de los componentes del nombre de una persona, representados por un objeto PersonNameComponents. Use esta clase para crear nombres localizados cuando muestre información de nombre de persona al usuario.


// iOS (9.0 and later), macOS (10.11 and later), tvOS (9.0 and later), watchOS (2.0 and later)
let nameFormatter = PersonNameComponentsFormatter()

let name =  "Mr. Steven Paul Jobs Jr."
// personNameComponents requires iOS (10.0 and later)
if let nameComps  = nameFormatter.personNameComponents(from: name) {
    nameComps.namePrefix   // Mr.
    nameComps.givenName    // Steven
    nameComps.middleName   // Paul
    nameComps.familyName   // Jobs
    nameComps.nameSuffix   // Jr.

    // It can also be configured to format your names
    // Default (same as medium), short, long or abbreviated

    nameFormatter.style = .default
    nameFormatter.string(from: nameComps)   // "Steven Jobs"

    nameFormatter.style = .short
    nameFormatter.string(from: nameComps)   // "Steven"

    nameFormatter.style = .long
    nameFormatter.string(from: nameComps)   // "Mr. Steven Paul Jobs jr."

    nameFormatter.style = .abbreviated
    nameFormatter.string(from: nameComps)   // SJ

    // It can also be use to return an attributed string using annotatedString method
    nameFormatter.style = .long
    nameFormatter.annotatedString(from: nameComps)   // "Mr. Steven Paul Jobs jr."
}

ingrese la descripción de la imagen aquí

editar / actualizar:

Swift 5 o posterior

Para dividir una cadena por caracteres que no sean letras, podemos usar la nueva propiedad Character isLetter:

let fullName = "First Last"

let components = fullName.split{ !$0.isLetter }
print(components)  // "["First", "Last"]\n"
Leo Dabus
fuente
1
@DarrellRoot solo necesitas mapear las subcadenasfullName.split { $0.isWhitespace }.map(String.init)
Leo Dabus
2
Me encanta esa nueva API, pero tenga en cuenta que devuelve Subcadenas. Necesitaba cadenas (y quería let words = line.split{ $0.isWhitespace }.map{ String($0)} dividirme en el espacio en blanco en general), así que hice esto: Gracias @LeoDabus por su versión (mi comentario original no tenía código). También sugiero mover la versión Swift 5 a la parte superior de la respuesta.
Darrell Root
53

Como alternativa a la respuesta de WMios, también puede usar componentsSeparatedByCharactersInSet, lo que puede ser útil en el caso de que tenga más separadores (espacio en blanco, coma, etc.).

Con su aporte específico:

let separators = NSCharacterSet(charactersInString: " ")
var fullName: String = "First Last";
var words = fullName.componentsSeparatedByCharactersInSet(separators)

// words contains ["First", "Last"]

Usando múltiples separadores:

let separators = NSCharacterSet(charactersInString: " ,")
var fullName: String = "Last, First Middle";
var words = fullName.componentsSeparatedByCharactersInSet(separators)

// words contains ["Last", "First", "Middle"]
Antonio
fuente
2
La respuesta más útil en mi opinión, ya que es posible que desee permitir la separación de cadenas con ,o con ;cualquier otro separador
Chris
49

Swift 4

let words = "these words will be elements in an array".components(separatedBy: " ")
Poli
fuente
34

El problema del espacio en blanco

En general, las personas reinventan este problema y las malas soluciones una y otra vez. ¿Es este un espacio? "" y qué pasa con "\ n", "\ t" o algún carácter de espacio en blanco Unicode que nunca has visto, en gran parte porque es invisible. Si bien puedes salirte con la tuya

Una solución débil

import Foundation
let pieces = "Mary had little lamb".componentsSeparatedByString(" ")

Si alguna vez necesita sacudirse la realidad, vea un video de WWDC sobre cadenas o fechas. En resumen, casi siempre es mejor permitir que Apple resuelva este tipo de tarea mundana.

Solución robusta: use NSCharacterSet

La manera de hacer esto correctamente, en mi humilde opinión, es usar, NSCharacterSetya que, como se dijo anteriormente, su espacio en blanco podría no ser lo que esperaba y Apple ha proporcionado un conjunto de caracteres de espacio en blanco. Para explorar los diversos conjuntos de caracteres proporcionados, consulte la documentación del desarrollador NSCharacterSet de Apple y luego, solo entonces, aumente o construya un nuevo conjunto de caracteres si no se ajusta a sus necesidades.

NSCharacterSet espacios en blanco

Devuelve un conjunto de caracteres que contiene los caracteres en la Categoría general Unicode Zs y TABULACIÓN DE CARACTERES (U + 0009).

let longerString: String = "This is a test of the character set splitting system"
let components = longerString.components(separatedBy: .whitespaces)
print(components)
Cameron Lowell Palmer
fuente
2
Convenido. Lo primero que se me ocurrió después de ver las respuestas divididas por "" es: ¿Qué sucede si el texto de entrada contiene varios espacios consecutivos? ¿Qué pasa si tiene pestañas? Espacio de ancho completo (CJK)? etc.
Nicolas Miari
31

En Swift 4.2 y Xcode 10

//This is your str
let str = "This is my String" //Here replace with your string

Opción 1

let items = str.components(separatedBy: " ")//Here replase space with your value and the result is Array.
//Direct single line of code
//let items = "This is my String".components(separatedBy: " ")
let str1 = items[0]
let str2 = items[1]
let str3 = items[2]
let str4 = items[3]
//OutPut
print(items.count)
print(str1)
print(str2)
print(str3)
print(str4)
print(items.first!)
print(items.last!)

opcion 2

let items = str.split(separator: " ")
let str1 = String(items.first!)
let str2 = String(items.last!)
//Output
print(items.count)
print(items)
print(str1)
print(str2)

Opción 3

let arr = str.split {$0 == " "}
print(arr)

Opcion 4

let line = "BLANCHE:   I don't want realism. I want magic!"
print(line.split(separator: " "))
// Prints "["BLANCHE:", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]"

Por la documentación de Apple ...

let line = "BLANCHE:   I don't want realism. I want magic!"
print(line.split(separator: " "))
// Prints "["BLANCHE:", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]"

print(line.split(separator: " ", maxSplits: 1))//This can split your string into 2 parts
// Prints "["BLANCHE:", "  I don\'t want realism. I want magic!"]"

print(line.split(separator: " ", maxSplits: 2))//This can split your string into 3 parts

print(line.split(separator: " ", omittingEmptySubsequences: false))//array contains empty strings where spaces were repeated.
// Prints "["BLANCHE:", "", "", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]"

print(line.split(separator: " ", omittingEmptySubsequences: true))//array not contains empty strings where spaces were repeated.
print(line.split(separator: " ", maxSplits: 4, omittingEmptySubsequences: false))
print(line.split(separator: " ", maxSplits: 3, omittingEmptySubsequences: true))
iOS
fuente
23

Swift 4 hace que sea mucho más fácil dividir caracteres, solo use la nueva función de división para cadenas.

Ejemplo: let s = "hi, hello" let a = s.split(separator: ",") print(a)

Ahora tienes una matriz con 'hola' y 'hola'.

Jeroen Zonneveld
fuente
Tenga en cuenta que esto no devuelve una matriz de String, sino una matriz de Substring que es incómodo de usar.
Lirik
19

Actualización para Swift 5 y la forma más sencilla

let paragraph = "Bob hit a ball, the hit BALL flew far after it was hit. Hello! Hie, How r u?"

let words = paragraph.components(separatedBy: [",", " ", "!",".","?"])

Esto imprime,

["Bob", "hit", "a", "ball", "", "the", "hit", "BALL", "fly", "far", "after", "it", "was "," hit "," "," Hello "," "," Hie "," "," How "," r "," u "," "]

Sin embargo, si desea filtrar una cadena vacía,

let words = paragraph.components(separatedBy: [",", " ", "!",".","?"]).filter({!$0.isEmpty})

Salida,

["Bob", "hit", "a", "ball", "the", "hit", "BALL", "fly", "far", "after", "it", "was", " presione "," Hola "," Hie "," Cómo "," r "," u "]

Pero asegúrate, la Fundación es importada

Mithra Singam
fuente
17

Swift 3

let line = "AAA    BBB\t CCC"
let fields = line.components(separatedBy: .whitespaces).filter {!$0.isEmpty}
  • Devuelve tres cuerdas AAA, BBByCCC
  • Filtra campos vacíos
  • Maneja múltiples espacios y caracteres de tabulación.
  • Si desea manejar nuevas líneas, reemplácelas .whitespacescon.whitespacesAndNewlines
tepl
fuente
15

Swift 4, Xcode 10 y iOS 12 Update 100% funcionando

let fullName = "First Last"    
let fullNameArr = fullName.components(separatedBy: " ")
let firstName = fullNameArr[0] //First
let lastName = fullNameArr[1] //Last

Consulte la documentación de Apple aquí para obtener más información.

Xcodian Solangi
fuente
13

Xcode 8.0 / Swift 3

let fullName = "First Last"
var fullNameArr = fullName.components(separatedBy: " ")

var firstname = fullNameArr[0] // First
var lastname = fullNameArr[1] // Last

Largo camino:

var fullName: String = "First Last"
fullName += " " // this will help to see the last word

var newElement = "" //Empty String
var fullNameArr = [String]() //Empty Array

for Character in fullName.characters {
    if Character == " " {
        fullNameArr.append(newElement)
        newElement = ""
    } else {
        newElement += "\(Character)"
    }
}


var firsName = fullNameArr[0] // First
var lastName = fullNameArr[1] // Last
NikaE
fuente
9

Tuve un escenario en el que varios caracteres de control pueden estar presentes en la cadena que quiero dividir. En lugar de mantener una serie de estos, solo dejo que Apple maneje esa parte.

Lo siguiente funciona con Swift 3.0.1 en iOS 10:

let myArray = myString.components(separatedBy: .controlCharacters)
CodeBender
fuente
8

Encontré un caso interesante, que

Método 1

var data:[String] = split( featureData ) { $0 == "\u{003B}" }

Cuando utilicé este comando para dividir algún símbolo de los datos que se cargaron desde el servidor , se puede dividir durante la prueba en el simulador y sincronizarse con el dispositivo de prueba, pero no se dividirá en la aplicación de publicación y Ad Hoc

Me llevó mucho tiempo rastrear este error, podría maldecir de alguna versión Swift, o alguna versión de iOS o ninguno

No se trata también del código HTML, ya que trato de stringByRemovingPercentEncoding y todavía no funciona

Además 10/10/2015

en Swift 2.0, este método se ha cambiado a

var data:[String] = featureData.split {$0 == "\u{003B}"}

método 2

var data:[String] = featureData.componentsSeparatedByString("\u{003B}")

Cuando utilicé este comando, puede dividir los mismos datos que se cargan correctamente desde el servidor


Conclusión, realmente sugiero usar el método 2

string.componentsSeparatedByString("")
Sruit A.Suk
fuente
1
Yo diría que esto está cerca del estado de "no una respuesta", ya que es principalmente un comentario sobre las respuestas existentes. Pero está señalando algo importante.
rickster
8

La mayoría de estas respuestas asumen que la entrada contiene un espacio, no un espacio en blanco , y un solo espacio en eso. Si puede hacer esa suposición con seguridad, entonces la respuesta aceptada (de bennett) es bastante elegante y también el método con el que iré cuando pueda.

Cuando no podemos hacer esa suposición, una solución más sólida necesita cubrir las siguientes situaciones que la mayoría de las respuestas aquí no consideran:

  • pestañas / líneas nuevas / espacios (espacios en blanco), incluidos los caracteres recurrentes
  • espacios en blanco iniciales / finales
  • Caracteres de línea nueva de Apple / Linux ( \n) y Windows ( \r\n)

Para cubrir estos casos, esta solución utiliza expresiones regulares para convertir todos los espacios en blanco (incluidos los caracteres recurrentes y de nueva línea de Windows) en un solo espacio, recorta y luego divide en un solo espacio:

Swift 3:

let searchInput = "  First \r\n \n \t\t\tMiddle    Last "
let searchTerms = searchInput 
    .replacingOccurrences(
        of: "\\s+",
        with: " ",
        options: .regularExpression
    )
    .trimmingCharacters(in: .whitespaces)
    .components(separatedBy: " ")

// searchTerms == ["First", "Middle", "Last"]
DonVaughn
fuente
6

O sin cierres, puedes hacer esto en Swift 2:

let fullName = "First Last"
let fullNameArr = fullName.characters.split(" ")
let firstName = String(fullNameArr[0])
Rauli Rikama
fuente
6

Pasos para dividir una cadena en una matriz en Swift 4.

  1. asignar cadena
  2. basado en @ división.

Nota: variableName.components (separados por: "palabra clave dividida")

let fullName: String = "First Last @ triggerd event of the session by session storage @ it can be divided by the event of the trigger."
let fullNameArr = fullName.components(separatedBy: "@")
print("split", fullNameArr)
Vidhyapathi Kandhasamy
fuente
4

Swift 4

let string = "loremipsum.dolorsant.amet:"

let result = string.components(separatedBy: ".")

print(result[0])
print(result[1])
print(result[2])
print("total: \(result.count)")

Salida

loremipsum
dolorsant
amet:
total: 3
MrMins
fuente
3

Digamos que tiene una variable llamada "Hello World" y si desea dividirla y almacenarla en dos variables diferentes, puede usarla así:

var fullText = "Hello World"
let firstWord = fullText.text?.components(separatedBy: " ").first
let lastWord = fullText.text?.components(separatedBy: " ").last
Parth Barot
fuente
2
let str = "one two"
let strSplit = str.characters.split(" ").map(String.init) // returns ["one", "two"]

Xcode 7.2 (7C68)

Amr Lotfy
fuente
2

Swift 2.2 Error Handling & capitalizedString Added:

func setFullName(fullName: String) {
    var fullNameComponents = fullName.componentsSeparatedByString(" ")

    self.fname = fullNameComponents.count > 0 ? fullNameComponents[0]: ""
    self.sname = fullNameComponents.count > 1 ? fullNameComponents[1]: ""

    self.fname = self.fname!.capitalizedString
    self.sname = self.sname!.capitalizedString
}
Aqib Mumtaz
fuente
2

El manejo de cadenas sigue siendo un desafío en Swift y sigue cambiando significativamente, como puede ver en otras respuestas. Esperemos que las cosas se calmen y se vuelva más simple. Esta es la forma de hacerlo con la versión 3.0 actual de Swift con múltiples caracteres separadores.

Swift 3:

let chars = CharacterSet(charactersIn: ".,; -")
let split = phrase.components(separatedBy: chars)

// Or if the enums do what you want, these are preferred. 
let chars2 = CharacterSet.alphaNumerics // .whitespaces, .punctuation, .capitalizedLetters etc
let split2 = phrase.components(separatedBy: chars2)
poseer
fuente
2

Estaba buscando una división floja , como PHP explodedonde se incluyen secuencias vacías en la matriz resultante, esto funcionó para mí:

"First ".split(separator: " ", maxSplits: 1, omittingEmptySubsequences: false)

Salida:

["First", ""]
AamirR
fuente
2

Esto proporciona una variedad de partes divididas directamente

var fullNameArr = fullName.components(separatedBy:" ")

entonces puedes usar así,

var firstName: String = fullNameArr[0]
var lastName: String? = fullnameArr[1]
Yodagama
fuente
2

Solo el splites la respuesta correcta, aquí están las diferencias para más de 2 espacios.

var temp = "Hello world     ni hao"
let arr  = temp.components(separatedBy: .whitespacesAndNewlines)
// ["Hello", "world", "", "", "", "", "ni", "hao"]
let arr2 = temp.components(separatedBy: " ")
// ["Hello", "world", "", "", "", "", "ni", "hao"]
let arr3 = temp.split(whereSeparator: {$0 == " "})
// ["Hello", "world", "ni", "hao"]
mistdon
fuente
1

Esto ha cambiado nuevamente en Beta 5. ¡Weee! Ahora es un método en CollectionType

Antiguo:

var fullName = "First Last"
var fullNameArr = split(fullName) {$0 == " "}

Nuevo:

var fullName = "First Last"
var fullNameArr = fullName.split {$0 == " "}

Notas de lanzamiento de manzanas

Daniel H.
fuente
1

Para swift 2, XCode 7.1:

let complete_string:String = "Hello world"
let string_arr =  complete_string.characters.split {$0 == " "}.map(String.init)
let hello:String = string_arr[0]
let world:String = string_arr[1]
abinop
fuente
1

Aquí hay un algoritmo que acabo de construir, que dividirá uno Stringpor cualquiera Characterde la matriz y, si hay algún deseo de mantener las subcadenas con caracteres divididos, se podría establecer el swallowparámetro true.

Xcode 7.3 - Swift 2.2:

extension String {

    func splitBy(characters: [Character], swallow: Bool = false) -> [String] {

        var substring = ""
        var array = [String]()
        var index = 0

        for character in self.characters {

            if let lastCharacter = substring.characters.last {

                // swallow same characters
                if lastCharacter == character {

                    substring.append(character)

                } else {

                    var shouldSplit = false

                    // check if we need to split already
                    for splitCharacter in characters {
                        // slit if the last character is from split characters or the current one
                        if character == splitCharacter || lastCharacter == splitCharacter {

                            shouldSplit = true
                            break
                        }
                    }

                    if shouldSplit {

                        array.append(substring)
                        substring = String(character)

                    } else /* swallow characters that do not equal any of the split characters */ {

                        substring.append(character)
                    }
                }
            } else /* should be the first iteration */ {

                substring.append(character)
            }

            index += 1

            // add last substring to the array
            if index == self.characters.count {

                array.append(substring)
            }
        }

        return array.filter {

            if swallow {

                return true

            } else {

                for splitCharacter in characters {

                    if $0.characters.contains(splitCharacter) {

                        return false
                    }
                }
                return true
            }
        }
    }
}

Ejemplo:

"test text".splitBy([" "]) // ["test", "text"]
"test++text--".splitBy(["+", "-"], swallow: true) // ["test", "++" "text", "--"]
DevAndArtist
fuente