when dictionaries collection array arrays string swift newline

arrays - dictionaries - swift array initialization



Cómo dividir una cadena por nuevas líneas en Swift (8)

Tengo una cadena que obtuve de un archivo de texto.

Archivo de texto:

Line 1 Line 2 Line 3 ...

Quiero convertirlo en una matriz, un elemento de matriz por línea.

[ "Line 1", "Line 2", "Line 3", ... ]

Dependiendo de cómo se guardó el archivo, la cadena podría tomar una de las siguientes formas:

  • string = "Line 1/nLine 2/nLine 3/n..." donde /n es el nuevo carácter de línea (avance de línea)

  • string = "Line 1/r/nLine 2/r/nLine 3/r/n..." donde /r es el carácter de retorno de carro.

Según tengo entendido, /n se usa comúnmente en Apple / Linux hoy, mientras que /r/n se usa en Windows.

¿Cómo divido una cadena en cualquier salto de línea para obtener una matriz de cadena sin elementos vacíos?

Actualizar

Hay varias soluciones que funcionan a continuación. En este punto, no tengo ninguna razón convincente para elegir una más correcta que las otras. Algunos factores que pueden influir en la elección podrían ser (1) cuán "veloz" es y (2) qué tan rápido es para cuerdas muy largas. Puede proporcionar comentarios votando uno o más de ellos y / o dejando un comentario.

Vea mi respuesta resumida aquí


¿Cómo divido una cadena en cualquier salto de línea para obtener una matriz de cadena sin elementos vacíos?

Ya casi estabas allí, es solo el cierre final que es diferente aquí:

let array = stringFromFile.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()).filter{!$0.isEmpty}

Que es lo mismo que:

let newLineChars = NSCharacterSet.newlineCharacterSet() // newline characters defined as (U+000A–U+000D, U+0085) let array = stringFromFile.componentsSeparatedByCharactersInSet(newLineChars).filter{!$0.isEmpty}

ETA: se eliminaron los corchetes adicionales innecesarios en el cierre posterior


En Swift 2, la función de split nivel superior ahora es un método en CollectionType (al que se ajusta cada una de las "vistas de caracteres" de String ). Hay dos versiones del método, desea la que toma un cierre como predicado para indicar si un elemento dado debe tratarse como un separador.

Puede obtener la colección de caracteres de la cadena como una colección de caracteres string.utf16 usando string.utf16 , haciéndolos compatibles con las API NSCharacterSet . De esta forma, podemos verificar fácilmente dentro del cierre si un determinado carácter de la cadena es miembro del conjunto de caracteres de nueva línea.

Vale la pena señalar que split(_:) devolverá una SubSequence de caracteres (básicamente un Slice ), por lo que debe transformarse nuevamente en una matriz de Strings que generalmente es más útil. He hecho esto a continuación usando flatMap(String.init) : el inicializador UTF16View en String está disponible, por lo que el uso de flatMap ignorará cualquier valor nil que pueda devolverse, asegurando que obtenga una matriz de cadenas no opcionales.

Entonces, para una forma agradable de hacer esto:

let str = "Line 1/nLine 2/r/nLine 3/n" let newlineChars = NSCharacterSet.newlineCharacterSet() let lines = str.utf16.split { newlineChars.characterIsMember($0) }.flatMap(String.init) // lines = ["Line 1", "Line 2", "Line 3"]

Lo que hace que esto sea agradable es que el método de split tiene un parámetro allowEmptySubsequences , que garantiza que no recibas ninguna secuencia de caracteres vacía en el resultado. Esto es false de forma predeterminada, por lo que no necesita especificarlo en absoluto.

Editar

Si desea evitar completamente NSCharacterSet , puede dividir fácilmente la colección de Character compatibles con Unicode.

let lines = str.characters.split { $0 == "/n" || $0 == "/r/n" }.map(String.init)

Swift puede tratar "/r/n" como un solo clúster de grafema extendido, usándolo como un solo Character para la comparación en lugar de crear una String . También tenga en cuenta que el inicializador para crear una cadena a partir de un Character no está disponible, por lo que podemos usar el map .


Esta respuesta es un resumen de las otras soluciones ya dadas. Viene de mi respuesta más completa , pero sería útil tener las opciones de métodos reales disponibles aquí.

Las nuevas líneas generalmente se hacen con el carácter /n , pero también se pueden hacer con /r/n (de los archivos guardados en Windows).

Soluciones

1. componentsSeparatedByCharactersInSet

let multiLineString = "Line 1/nLine 2/r/nLine 3/n" let newlineChars = NSCharacterSet.newlineCharacterSet() let lineArray = multiLineString.componentsSeparatedByCharactersInSet(newlineChars).filter{!$0.isEmpty} // "[Line 1, Line 2, Line 3]"

Si no se usara el filter , /r/n produciría un elemento de matriz vacío porque se cuenta como dos caracteres y, por lo tanto, separa la cadena dos veces en la misma ubicación.

2. split

let multiLineString = "Line 1/nLine 2/r/nLine 3/n" let newlineChars = NSCharacterSet.newlineCharacterSet() let lineArray = multiLineString.utf16.split { newlineChars.characterIsMember($0) }.flatMap(String.init) // "[Line 1, Line 2, Line 3]"

o

let multiLineString = "Line 1/nLine 2/r/nLine 3/n" let lineArray = multiLineString.characters.split { $0 == "/n" || $0 == "/r/n" }.map(String.init) // "[Line 1, Line 2, Line 3]"

Aquí /r/n se cuenta como un solo personaje Swift (un grupo de grafemas extendido)

3. enumerateLines

let multiLineString = "Line 1/nLine 2/r/nLine 3/n" var lineArray = [String]() multiLineString.enumerateLines { (line, stop) -> () in lineArray.append(line) } // "[Line 1, Line 2, Line 3]"

Para obtener más información sobre la sintaxis enumerateLine , consulte también esta respuesta .

Notas:

  • una cadena de varias líneas no suele mezclar tanto /r/n como /n pero estoy haciendo esto aquí para mostrar que estos métodos pueden manejar ambos formatos.
  • NSCharacterSet.newlineCharacterSet() son caracteres de nueva línea definidos como (U + 000A – U + 000D, U + 0085), que incluyen /r y /n .
  • Esta respuesta es un resumen de las respuestas a mi pregunta anterior . Lea esas respuestas para más detalles.

Para el registro, Swift''s Foundation CharacterSet se puede usar dentro de la división:

alternativa 1

extension String { var lines: [String] { return split { String($0).rangeOfCharacter(from: .newlines) != nil }.map(String.init) } }

alternativa 2

extension String { var lines: [String] { return split { CharacterSet.newlines.contains($0.unicodeScalars.first!) }.map(String.init) } }


en Xcode 8.2, Swift 3.0.1:

Utilice los componentes del método NSString (separados por :)

let text = "line1/nline2" let array = text.components(separatedBy: CharacterSet.newlines)

O use el método String enumerateLines , como la respuesta de Leo Dabus


Swift 4:

Recomendaría guardar primero su CSV en una cadena si aún no lo ha hecho, luego "limpiar" la cadena eliminando retornos de carro innecesarios

let dataString = String(data: yourData!, encoding: .utf8)! var cleanFile = dataString.replacingOccurrences(of: "/r", with: "/n") cleanFile = cleanFile.replacingOccurrences(of: "/n/n", with: "/n")

Lo anterior le dará una cadena con el formato más deseable, luego puede separar la cadena usando / n como su separador:

let csvStrings = cleanFile.components(separatedBy: ["/n"])

Ahora tiene una serie de 3 elementos como:

["Línea1", "Línea2", "Línea3"]

Estoy usando un archivo CSV y después de hacer esto, estoy dividiendo los elementos en componentes, así que si sus elementos fueran algo como:

["Line1, Line2, Line3", "LineA, LineB, LineC"]

let component0 = csvStrings[0].components(separatedBy: [","]) // ["Line1","Line2","Line3"] let component1 = csvStrings[1].components(separatedBy: [","]) // ["LineA","LineB","LineC"]


Swift 5 o posterior

Puede dividir su String utilizando la nueva propiedad de Character isNewline :

let sentence = "Line 1/nLine 2/nLine 3/n" var lines = sentence.split { $0.isNewline } print(lines) // "[Line 1, Line 2, Line 3]"

Respuesta original

Puede usar el método de cadena enumerateLines :

Enumera todas las líneas de una cadena.

Swift 3 o posterior

let sentence = "Line 1/nLine 2/nLine 3/n" var lines: [String] = [] sentence.enumerateLines { line, _ in lines.append(line) } print(lines) // "[Line 1, Line 2, Line 3]"

extension String { var lines: [String] { var result: [String] = [] enumerateLines { line, _ in result.append(line) } return result } }

Uso:

let sentence2 = "Line 4/nLine 5/nLine 6/n" let sentence2Lines = sentence2.lines print(sentence2Lines) // ["Line 4", "Line 5", "Line 6"] let sentence3 = "Line 7/r/nLine 8/r/nLine 9/r/n" let sentence3Lines = sentence3.lines print(sentence3Lines) // "[Line 7, Line 8, Line 9]"


let test1 = "Line1/n/rLine2/nLine3/rLine4" let t1 = test1.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) let t2 = t1.filter{ $0 != "" } let t3 = t1.filter{ !$0.isEmpty }