Dividir uma String em uma matriz no Swift?

686

Digamos que eu tenha uma string aqui:

var fullName: String = "First Last"

Eu quero dividir a base da string em espaço em branco e atribuir os valores às suas respectivas variáveis

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

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

Além disso, às vezes os usuários podem não ter um sobrenome.

blee908
fonte
13
Oi, eu não tenho meu Mac para verificar. Mas você pode tentar 'fullName.componentsSeparatedByString (string: "")' Não copie e cole, use a função de preenchimento automático para obter a função correta.
David Gölzhäuser
Se você é única divisão por um personagem, usando fullName.utf8.split( <utf-8 character code> )funciona tão bem (substitua .utf8com .utf16a UTF-16). Por exemplo, a divisão +poderia ser feita usandofullName.utf8.split(43)
Jojodmo
Além disso, às vezes os sobrenomes têm espaços neles, como em "Daphne du Maurier" ou "Charles de Lint"
Berry

Respostas:

784

A maneira Swift é usar a splitfunção global , assim:

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

com Swift 2

No Swift 2, o uso da divisão se torna um pouco mais complicado devido à introdução do tipo interno CharacterView. Isso significa que String não adota mais os protocolos SequenceType ou CollectionType e você deve usar a .characterspropriedade para acessar uma representação do tipo CharacterView de uma instância de String. (Nota: o CharacterView adota os protocolos SequenceType e 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
fonte
98
Nos meus testes, componentsSeparatedByString geralmente é significativamente mais rápido, especialmente quando se lida com strings que exigem divisão em várias partes. Mas, para o exemplo listado pelo OP, ambos devem ser suficientes.
Casey Perkins #
9
A partir do Xcode 6.2b3, a divisão pode ser usada como split("a:b::c:", {$0 == ":"}, maxSplit: Int.max, allowEmptySlices: false).
Pascal
14
Lembre-se de que você ainda precisará usar o componentsSeparatedByString()método antigo se o seu separador tiver mais do que um único caractere. E por mais legal que seja let (firstName, lastName) = split(fullName) {$0 == ' '}, isso não funciona, infelizmente.
NRitH 17/02/2015
3
@Kashif então você poderia usar split("a,b;c,d") {$0 == "," || $0 == ";"}ousplit("a,b;c,d") {contains(",;", $0)}
Ethan
4
O código correto para o Xcode 7.0 é permitido fullNameArr = fullName.characters.split {$ 0 == ""} .map (String.init). Tentei editar, mas foi rejeitado.
skagedal 22/09/2015
1015

Basta chamar o componentsSeparatedByStringmétodo no seufullName

import Foundation

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

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

Atualização 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
fonte
3
Observe que isso é realmente um subjacente NSString(o Swift os troca automaticamente ao importar Foundation).
Can
1
O que não é mais o caso no Swift 1.2, no qual a Apple não converte mais a String do Swift em NSString automaticamente.
elcuco
6
Esta resposta funciona no Xcode 7 beta 4 e no Swift 2.0. O Xcode agora conclui automaticamente os métodos Foundation nos objetos Swift String sem conversão de tipo para um NSString, o que não é o caso no Xcode 6.4 com Swift 1.2.
21815 Andrew Andrew
1
Não funcionou no REPL até importar a Foundation.
Velizar Hristov
1
Isso funciona exatamente como o esperado (por exemplo, fullNameArr é um [String]) no Xcode 7.2.
Jon Cox
185

O método mais fácil de fazer isso é usar 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
fonte
Isso está documentado em algum lugar, Maury? E se eu precisar dividir algo que não seja um único personagem?
NRitH 17/02
10
@NRitH consideram .componentsSeparatedByCharactersInSet(.whitespaceAndNewlineCharacterSet())
rmp251
@Crashalot existem duas funções: componentsSeparatedByStringecomponentsSeparatedByCharactersInSet
rmp251
131

Swift Dev. 4.0 (24 de maio de 2017)

Uma nova função splitno Swift 4 ( Beta ).

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

Resultado:

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

Acessando valores:

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

Xcode 8.1 / Swift 3.0.1

Aqui está o caminho de vários delimitadores com array.

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

Resultado:

["12", "37", "2", "5"]
LugiHaue
fonte
8
Certifique-se de adicionar import Foundationà classe em que você está usando isso. #SavedYouFiveMinutes
Adrian
4
Atenção (Swift 4): Se você tem uma string como let a="a,,b,c"e usa, a.split(separator: ",")obtém uma matriz como ["a", "b", c"]por padrão. Isso pode ser alterado usando o omittingEmptySubsequences: falseque é verdadeiro por padrão.
precisa saber é o seguinte
2
Alguma divisão de vários caracteres no Swift 4+?
Pkamb # 7/18
57

Swift 4 ou posterior

Se você apenas precisar formatar corretamente o nome de uma pessoa, poderá usar PersonNameComponentsFormatter .

A classe PersonNameComponentsFormatter fornece representações localizadas dos componentes do nome de uma pessoa, conforme representado por um objeto PersonNameComponents. Use esta classe para criar nomes localizados ao exibir informações de nome de pessoa para o usuário.


// 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."
}

insira a descrição da imagem aqui

editar / atualizar:

Swift 5 ou posterior

Para apenas dividir uma string por caracteres que não sejam da letra, podemos usar a nova propriedade Character isLetter:

let fullName = "First Last"

let components = fullName.split{ !$0.isLetter }
print(components)  // "["First", "Last"]\n"
Leo Dabus
fonte
1
@DarrellRoot você só precisa mapear as substrings #fullName.split { $0.isWhitespace }.map(String.init)
Leo Dabus
2
Adoro essa nova API, mas lembre-se de que ela retorna Substrings. Eu precisava de Strings (e queria dividir em espaço em branco em geral), então fiz isso: let words = line.split{ $0.isWhitespace }.map{ String($0)} Obrigado @LeoDabus pela sua versão (meu comentário original tinha código ausente). Também sugiro mover a versão Swift 5 para o topo da resposta.
Darrell Root
53

Como alternativa à resposta do WMios, você também pode usar componentsSeparatedByCharactersInSet, o que pode ser útil no caso de haver mais separadores (espaço em branco, vírgula etc.).

Com sua entrada específica:

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

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

Usando vários separadores:

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

// words contains ["Last", "First", "Middle"]
Antonio
fonte
2
A maioria resposta útil na minha opinião, já que você pode querer para permitir a separação das cordas com ,ou ;ou qualquer outro separador
Chris
49

Swift 4

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

A questão do espaço em branco

Geralmente, as pessoas reinventam esse problema e soluções ruins repetidamente. Isso é um espaço? "" e quanto a "\ n", "\ t" ou algum caractere de espaço em branco unicode que você nunca viu, em grande parte porque é invisível. Enquanto você pode se safar

Uma solução fraca

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

Se você precisar controlar a realidade, assista a um vídeo da WWDC sobre sequências ou datas. Em resumo, é quase sempre melhor permitir que a Apple resolva esse tipo de tarefa mundana.

Solução robusta: Use NSCharacterSet

A maneira de fazer isso corretamente, IMHO, é usar, NSCharacterSetpois, como declarado anteriormente, seu espaço em branco pode não ser o que você espera e a Apple forneceu um conjunto de caracteres para espaço em branco. Para explorar os vários conjuntos de caracteres fornecidos, consulte a documentação do desenvolvedor NSCharacterSet da Apple e, somente então, aumente ou construa um novo conjunto de caracteres, se ele não atender às suas necessidades.

NSCharacterSet espaços em branco

Retorna um conjunto de caracteres contendo os caracteres na Categoria Geral Unicode Zs e CHARACTER TABULATION (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
fonte
2
Acordado. A primeira coisa que me ocorreu depois de ver as respostas divididas por "" é: O que acontece se o texto de entrada contiver vários espaços consecutivos? E se tiver guias? Espaço em largura total (CJK)? etc.
Nicolas Miari 01/07/16
31

No Swift 4.2 e no Xcode 10

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

Opção 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!)

opção 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)

Opção 3

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

Opção 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 documentação da 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
fonte
23

O Swift 4 facilita muito a divisão de caracteres, basta usar a nova função de divisão para Strings.

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

Agora você tem uma matriz com 'oi' e 'oi'.

Jeroen Zonneveld
fonte
Observe que isso não retorna uma matriz de String, mas uma matriz de Substring que é difícil de usar.
Lirik
19

Atualização para o Swift 5 e a maneira mais simples

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: [",", " ", "!",".","?"])

Isso imprime,

["Bob", "acerto", "a", "bola", "", "o", "acerto", "BOLA", "voou", "longe", "depois", "depois", "foi" foi " "," hit "," "," Olá "," "," Hie "," "," Como "," r "," u "," "]

No entanto, se você deseja filtrar a string vazia,

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

Resultado,

["Bob", "hit", "a", "ball", "the", "hit", "BALL", "voou", "long", "after", "it", "was", " pressione "," Olá "," Hie "," Como "," r "," u "]

Mas verifique se o Foundation é importado

Mithra Singam
fonte
17

Swift 3

let line = "AAA    BBB\t CCC"
let fields = line.components(separatedBy: .whitespaces).filter {!$0.isEmpty}
  • Retorna três cordas AAA, BBBeCCC
  • Filtra campos vazios
  • Manipula vários espaços e caracteres de tabulação
  • Se você deseja lidar com novas linhas, substitua .whitespacespor.whitespacesAndNewlines
tepl
fonte
15

Swift 4, Xcode 10 e iOS 12 atualizam 100% de funcionamento

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

Consulte a documentação da Apple aqui para obter mais informações.

Xcodian Solangi
fonte
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

Longo caminho:

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
fonte
9

Eu tive um cenário em que vários caracteres de controle podem estar presentes na string que eu quero dividir. Em vez de manter uma variedade dessas, apenas deixei a Apple lidar com essa parte.

O seguinte funciona com o Swift 3.0.1 no iOS 10:

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

Encontrei um caso interessante, que

Método 1

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

Quando usei esse comando para dividir algum símbolo dos dados carregados do servidor , ele pode ser dividido durante o teste no simulador e sincronizado com o dispositivo de teste, mas não será dividido no aplicativo de publicação e no Ad Hoc

Levo muito tempo para rastrear esse erro, ele pode ser amaldiçoado por alguma versão Swift ou por uma versão iOS ou por nenhuma

Também não é sobre o código HTML, já que tento stringByRemovingPercentEncoding e ainda não está funcionando

adição 10/10/2015

no Swift 2.0, esse método foi alterado para

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

método 2

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

Quando usei esse comando, ele pode dividir os mesmos dados carregados do servidor corretamente


Conclusão, eu realmente sugiro usar o método 2

string.componentsSeparatedByString("")
Sruit A.Suk
fonte
1
Eu diria que isso está próximo do status "não é uma resposta", pois é principalmente um comentário sobre as respostas existentes. Mas está apontando algo importante.
Rickster 29/07/2015
8

A maioria dessas respostas pressupõe que a entrada contenha um espaço - não um espaço em branco e um único espaço nele. Se você pode fazer essa suposição com segurança, a resposta aceita (do bennett) é bastante elegante e também o método que seguirei quando puder.

Quando não podemos fazer essa suposição, uma solução mais robusta precisa cobrir as seguintes descrições que a maioria das respostas aqui não considera:

  • guias / novas linhas / espaços (espaço em branco), incluindo caracteres recorrentes
  • espaço em branco à esquerda / à direita
  • Caracteres de nova linha Apple / Linux ( \n) e Windows ( \r\n)

Para cobrir esses casos, esta solução usa o regex para converter todos os espaços em branco (incluindo caracteres recorrentes e de nova linha do Windows) em um único espaço, apara e divide por um único espaço:

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
fonte
6

Ou sem fechamentos, você pode fazer exatamente isso no Swift 2:

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

Etapas para dividir uma string em uma matriz no Swift 4.

  1. atribuir string
  2. com base na divisão.

Nota: variableName.components (selectedBy: "split keyword")

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

Resultado

loremipsum
dolorsant
amet:
total: 3
MrMins
fonte
3

Digamos que você tenha uma variável chamada "Hello World" e, se quiser dividi-la e armazená-la em duas variáveis ​​diferentes, poderá usar o seguinte:

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

Xcode 7.2 (7C68)

Amr Lotfy
fonte
2

Manipulação de erro do Swift 2.2 & capitalizedString Adicionado:

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
fonte
2

O manuseio de cordas ainda é um desafio no Swift e continua mudando significativamente, como você pode ver em outras respostas. Espero que as coisas se acalmem e fiquem mais simples. Essa é a maneira de fazer isso com a versão 3.0 atual do Swift, com vários 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)
possuir
fonte
2

Eu estava procurando por uma divisão frouxa , como PHP, explodeonde sequências vazias são incluídas na matriz resultante, isso funcionou para mim:

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

Resultado:

["First", ""]
AamirR
fonte
2

Isso fornece uma variedade de partes separadas diretamente

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

então você pode usar assim,

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

Somente a splitresposta é correta, eis a diferença para mais de 2 espaços.

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
fonte
1

Isso mudou novamente no Beta 5. Weee! Agora é um método no CollectionType

Velho:

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

Novo:

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

Notas de versão de maçãs

Daniel H.
fonte
1

Para o Swift 2, o 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
fonte
1

Aqui está um algoritmo que acabei de construir, que dividirá um Stringpor qualquer Characterda matriz e, se houver algum desejo de manter as substrings com caracteres divididos, pode-se definir o 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
            }
        }
    }
}

Exemplo:

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