Konwertuj ciąg Swift na tablicę

133

Jak przekonwertować ciąg „Hello” na tablicę [„H”, „e”, „l”, „l”, „o”] w języku Swift?

W Objective-C użyłem tego:

NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[myString length]];
for (int i=0; i < [myString length]; i++) {
    NSString *ichar  = [NSString stringWithFormat:@"%c", [myString characterAtIndex:i]];
    [characters addObject:ichar];
}
Panie KLD
źródło

Odpowiedzi:

338

W Swift jest jeszcze łatwiej:

let string : String = "Hello 🐶🐮 🇩🇪"
let characters = Array(string)
println(characters)
// [H, e, l, l, o,  , 🐶, 🐮,  , 🇩🇪]

Wykorzystuje to fakt, że

  • Arraymogą być utworzone z SequenceType, i
  • Stringjest zgodny z SequenceTypeprotokołem, a jego generator sekwencji wylicza znaki.

A ponieważ łańcuchy Swift mają pełne wsparcie dla Unicode, działa to nawet ze znakami spoza „Basic Multilingual Plane” (np. 🐶) oraz z rozszerzonymi klastrami grafemowymi (takimi jak 🇩🇪, który w rzeczywistości składa się z dwóch skalarów Unicode).


Aktualizacja: od wersji Swift 2 String nie jest już zgodny z SequenceType, ale characterswłaściwość zapewnia sekwencję znaków Unicode:

let string = "Hello 🐶🐮 🇩🇪"
let characters = Array(string.characters)
print(characters)

Działa to również w Swift 3 .


Aktualizacja: Począwszy od Swift 4, String jest (ponownie) zbiorem jego Characters:

let string = "Hello 🐶🐮 🇩🇪"
let characters = Array(string)
print(characters)
// ["H", "e", "l", "l", "o", " ", "🐶", "🐮", " ", "🇩🇪"]
Martin R.
źródło
1
Czy masz pojęcie, dlaczego próba łączenia ( let joined = ", ".join(characters);) tablicy powoduje 'String' is not identical to 'Character'błąd?
Mohamad
3
@Mohamad: wyliczenie ciągu tworzy sekwencję znaków, ale ", ".join(...)oczekuje tablicy ciągów. Odpowiedź devxoul poniżej pokazuje, jak można podzielić na tablicę ciągów.
Martin R
2
@Fonix: charactersto zbiór i widok znaków w postaci łańcuchów. Utworzenie tablicy ze znaków powoduje utworzenie kopii. - Oczywiście można uzyskać bezpośredni dostęp do postaci: for i in string.characters.indices { print(string.characters[i]) }lub po prostufor c in string.characters { print(c) }
Martin R
2
@Fonix: ... Z drugiej strony, losowe indeksowanie w łańcuchach może być powolne i korzystne może być jednorazowe utworzenie tablicy ze wszystkimi znakami. Przykład: stackoverflow.com/questions/40371929/… .
Martin R
2
@DaniSpringer: Swift 4 jest obecnie w wersji beta, będziesz potrzebować Xcode 9 beta: developer.apple.com/swift/resources .
Martin R
102

Edytuj (Swift 4)

W Swift 4 nie musisz charactersużywać map(). Po prostu zrób map()na String.

let letters = "ABC".map { String($0) }
print(letters) // ["A", "B", "C"]
print(type(of: letters)) // Array<String>

Lub jeśli wolisz krótszy: "ABC".map(String.init)(2 bajty 😀)

Edytuj (Swift 2 i Swift 3)

W Swift 2 i Swift 3 możesz użyć map()funkcji do characterswłaściwości.

let letters = "ABC".characters.map { String($0) }
print(letters) // ["A", "B", "C"]

Oryginał (Swift 1.x)

Zaakceptowana odpowiedź nie wydaje się najlepsza, ponieważ przekształcenie sekwencji Stringnie jest Stringsekwencją, ale Character:

$ swift
Welcome to Swift!  Type :help for assistance.
  1> Array("ABC")
$R0: [Character] = 3 values {
  [0] = "A"
  [1] = "B"
  [2] = "C"
}

To poniżej działa dla mnie:

let str = "ABC"
let arr = map(str) { s -> String in String(s) }

Odniesienie do funkcji globalnej map()jest tutaj: http://swifter.natecook.com/func/map/

devxoul
źródło
12
Nieco krócej:arr = map(str) { String($0) }
Martin R
1
ArrayZamiast tego użyj inicjalizatora:Array("ABC".characters)
chrisamanse
1
@chrisamanse, nie ma różnicy między "ABC".charactersi Array("ABC".characters).
devxoul,
2
Inaczej jest w języku Swift 3. "ABC".characterszwraca typ String.CharacterView. Aby przekonwertować go na tablicę, a konkretnie na typ, [Character]musiałbyś użyć na niej Arrayinicjatora.
chrisamanse
2
@chrisamanse Och, nie wiedziałem tego. Myliłem się. Dzięki za wskazanie tego. Nawiasem mówiąc, zamierzałem [String]zamiast tego, [Character]ponieważ op chciał tablicy ciągów :)
devxoul
22

Istnieje również ta przydatna funkcja na String: components (SeparatedBy: String)

let string = "1;2;3"
let array = string.components(separatedBy: ";")
print(array) // returns ["1", "2", "3"]

Dobrze radzi sobie z ciągami znaków oddzielonymi znakiem, takim jak „;” lub nawet „\ n”

Frédéric Adda
źródło
8

Zaktualizowano dla Swift 4

Oto 3 sposoby.

//array of Characters
let charArr1 = [Character](myString)

//array of String.element
let charArr2 = Array(myString)

for char in myString {
  //char is of type Character
}

W niektórych przypadkach to, czego ludzie naprawdę chcą, to sposób na przekształcenie łańcucha w tablicę małych ciągów o długości 1 znaku każdy. Oto super skuteczny sposób na zrobienie tego:

//array of String
var strArr = myString.map { String($0)}

Szybki 3

Oto 3 sposoby.

let charArr1 = [Character](myString.characters)
let charArr2 = Array(myString.characters)
for char in myString.characters {
  //char is of type Character
}

W niektórych przypadkach to, czego ludzie naprawdę chcą, to sposób na przekształcenie łańcucha w tablicę małych ciągów o długości 1 znaku każdy. Oto super skuteczny sposób na zrobienie tego:

var strArr = myString.characters.map { String($0)}

Lub możesz dodać rozszerzenie do String.

extension String {
   func letterize() -> [Character] {
     return Array(self.characters)
  }
}

Następnie możesz to nazwać tak:

let charArr = "Cat".letterize()
ScottyBlades
źródło
4
    let string = "hell0"
    let ar = Array(string.characters)
    print(ar)
William Hu
źródło
Nie było zmian pomiędzy Swift 2 i 3 w tym zakresie. To rozwiązanie jest identyczne z wersją Swift 2 na stackoverflow.com/a/25921323/1187415 .
Martin R
3

Odpowiedź Martina R jest najlepszym podejściem, a jak powiedział, ponieważ String jest zgodny z protokołem SquenceType, możesz również wyliczyć ciąg, uzyskując każdy znak w każdej iteracji.

let characters = "Hello"
var charactersArray: [Character] = []

for (index, character) in enumerate(characters) {
    //do something with the character at index
    charactersArray.append(character)
}

println(charactersArray)
Alberto Barrera
źródło
2
Lub po prostu for character in characters { charactersArray.append(character)}bezenumeration()
Tieme
3

W Swift 4, podobnie jak Stringzbiór Character, musisz użyćmap

let array1 = Array("hello") // Array<Character>
let array2 = Array("hello").map({ "\($0)" }) // Array<String>
let array3 = "hello".map(String.init) // Array<String>
onmyway133
źródło
3

Prostym sposobem na zrobienie tego jest mapprzejście do zmiennej i zwrócenie jej Characterjako String:

let someText = "hello"

let array = someText.map({ String($0) }) // [String]

Wynik powinien być ["h", "e", "l", "l", "o"].

atolit
źródło
1

Możesz również utworzyć rozszerzenie:

var strArray = "Hello, playground".Letterize()

extension String {
    func Letterize() -> [String] {
        return map(self) { String($0) }
    }
}
fabrizioM
źródło
1
func letterize() -> [Character] {
    return Array(self.characters)
}
Piotr Pszczółkowski
źródło
2
Czy możesz podać więcej informacji, dlaczego to zadziała? :)
pix
1
@pix Myślę, że miał na myśli funkcję zdefiniowaną w rozszerzeniu String. Dodam to do mojej odpowiedzi.
ScottyBlades
1

dla funkcji na łańcuchu: składniki (oddzielone przez: ciąg)

w Swift 5.1

zmienić na:

string.split(separator: "/")

Fat Panda
źródło