Swift - Podziel ciąg na wiele linii

Odpowiedzi:

444

Swift 4 obsługuje wieloliniowe literały łańcuchowe . Oprócz znaków nowej linii mogą także zawierać cytaty bez ukrycia.

var text = """
    This is some text
    over multiple lines
    """

Starsze wersje Swift nie pozwalają mieć jednego literału w wielu wierszach, ale można dodawać razem literały w wielu wierszach:

var text = "This is some text\n"
         + "over multiple lines\n"
Connor
źródło
2
Problem w tym podejściu polega na tym, że możesz łatwo dotrzeć do zbyt wielu „kontynuowanych” linii w Swift (od Xcode 6.2 beta), gdzie narzeka, że ​​wyrażenie jest „zbyt złożone, aby można je było rozwiązać w rozsądnym czasie” i rozważyć rozłamanie sprowadza się to do prostszych wyrażeń. To brzydkie, ale wystarczająco łatwe do osiągnięcia, po prostu zawiń sekcje w pareny.
jasne
8
Nie zapomnij dodać spacji między cudzysłowem zamykającym a znakiem +, w przeciwnym razie pojawi się błąd „+” nie jest jednoznacznym operatorem postfiksowym
Orlin Georgiev
To nadal działa, ale musisz ręcznie dodać \npostać. Na przykład w REPL: println("foo\n" + "bar")drukuje fooi barna osobnych wierszach.
Brian Gerstle,
Należy to naprawić w Xcode 7 „Łączenie literałów łańcuchowych Swift, w tym w wielu wierszach, to gwarantowana optymalizacja czasu kompilacji, nawet w -Onone.”, Adcdownload.apple.com/WWDC_2015/Xcode_7_beta/…
Kostiantyn Koval
2
Nie działa w przypadku wartości liczbowych enum, które używają ciągów :(
Lars Blumberg,
32

Użyłem rozszerzenia String, aby uzyskać ciągi wielowierszowe, unikając błędu zawieszenia kompilatora. Pozwala także określić separator, dzięki czemu można go używać trochę jak funkcji łączenia Pythona

extension String {
    init(sep:String, _ lines:String...){
        self = ""
        for (idx, item) in lines.enumerated() {
            self += "\(item)"
            if idx < lines.count-1 {
                self += sep
            }
        }
    }

    init(_ lines:String...){
        self = ""
        for (idx, item) in lines.enumerated() {
            self += "\(item)"
            if idx < lines.count-1 {
                self += "\n"
            }
        }
    }
}



print(
    String(
        "Hello",
        "World!"
    )
)
"Hello
World!"

print(
    String(sep:", ",
        "Hello",
        "World!"
    )
)
"Hello, World!"
McCornell
źródło
1
Te metody są idealne. Nawet w najnowszej wersji 1.2 Swift długie literały kompilują się bardzo wolno, a metody te pozwalają uniknąć tego narzutu.
phatmann
2
Dla każdego, kto używa Swift 2, enumerate(lines)jest terazlines.enumerate()
Jedidja
2
@mcornell To jest miłe, ale joinWithSeparatorczy zasadniczo nie robi tego samego? ["Hello", "World!"].joinWithSeparator(", ")
Dan Loewenherz
27

To była pierwsza rozczarowująca rzecz w Swift, którą zauważyłem. Prawie wszystkie języki skryptowe pozwalają na wieloliniowe ciągi znaków.

C ++ 11 dodał nieprzetworzone ciągi literałów, które pozwalają zdefiniować własny terminator

C # ma swoje @literals dla ciągów wieloliniowych.

Nawet zwykły C, a więc staromodny C ++ i Objective-C pozwalają na konkatentację po prostu poprzez umieszczenie wielu literałów obok siebie, więc cytaty są zwinięte. Białe znaki nie liczą się, gdy to robisz, więc możesz umieścić je w różnych wierszach (ale musisz dodać własne nowe linie):

const char* text = "This is some text\n"
                   "over multiple lines";

Ponieważ swift nie wie, że umieściłeś tekst w wielu wierszach, muszę naprawić próbkę Connora, podobnie jak moja próbka C, wyraźnie zaznaczając nowy wiersz:

var text:String = "This is some text \n" +
                  "over multiple lines"
Andy Dent
źródło
4
Jestem całkiem pewien, że istnieją w tym ograniczenia. Próbowałem podzielić ciąg znaków na 13 wierszy (jest to tekst informacyjny zawierający wiele wierszy). Nie tylko nie skończył się kompilować, ale zwalił mojego Maca na kolana. Jak mówię, nie mogę kategorycznie powiedzieć, że jest to problem, ale uwaga, wpływ jest dość zły.
Derek Knight
Rozbiłem się wiele razy, nawet przed kompilacją. Myślę, że proces „SourceKitService” odpowiedzialny za podświetlanie składni i uzupełnianie kodu (jak sądzę) jest również odpowiedzialny za te awarie.
Paul Brewczynski
@DerekKnight To błąd kompilatora, a nie ograniczenie językowe. Jeśli nadal występuje, powinieneś złożyć radar.
radex
@bluesm FYI: SourceKit to osobny proces, więc nie może zawiesić Xcode. Podświetla składnię i uzupełnia kod, poprawne, ale w tej chwili sama kompilacja żyje w procesie Xcode - dlatego błąd kompilatora czasami
usuwa
17

Ciągi wielowierszowe są możliwe od Swift 4.0, ale istnieją pewne zasady:

  1. Musisz zacząć i zakończyć swoje ciągi za pomocą trzech podwójnych cudzysłowów, """ .
  2. Treść ciągu powinna zaczynać się w osobnym wierszu.
  3. Zakończenie """powinno również rozpocząć się na jego własnej linii.

Poza tym możesz iść! Oto przykład:

let longString = """
When you write a string that spans multiple
lines make sure you start its content on a
line all of its own, and end it with three
quotes also on a line of their own.
Multi-line strings also let you write "quote marks"
freely inside your strings, which is great!
"""

Aby uzyskać więcej informacji, zobacz, co nowego w Swift 4 .

TwoStraws
źródło
Niestety nie działa to na placu zabaw Xcode 8.3.3. Pojawia się błąd „niezakończonego ciągu”.
James Foster,
Jak powiedziałem, ta funkcja jest nowa w Swift 4 - zainstaluj
łańcuch
16

Jak wskazał litso, wielokrotne użycie -Operatora +w jednym wyrażeniu może doprowadzić do zawieszenia się XCode Beta (właśnie sprawdzone za pomocą XCode 6 Beta 5): Xcode 6 Beta nie kompiluje się

Alternatywą dla multilinii strun na razie jest użycie tablicę łańcuchów i reduceto z +:

var text = ["This is some text ",
            "over multiple lines"].reduce("", +)

Lub, prawdopodobnie łatwiej, używając join:

var text = "".join(["This is some text ",
                    "over multiple lines"])
Jonas Reinsch
źródło
Wersja z redukcją działała dla mnie w wersji beta 6, ale dołączenie zgłosiło wyjątek.
Tristan Warner-Smith,
9

Swift 4 rozwiązał ten problem, zapewniając obsługę literału ciągów w wielu wierszach. Aby rozpocząć literał ciągów, dodaj trzy znaki podwójnego cudzysłowu („” ”) i naciśnij klawisz powrotu. Po naciśnięciu klawisza powrotu zacznij pisać ciągi znaków z dowolnymi zmiennymi, podziałami wierszy i podwójnymi cudzysłowami tak jak piszesz w notatniku lub dowolnym edytorze tekstu. Aby zakończyć dosłowny ciąg wieloliniowy, ponownie napisz (”” ”) w nowym wierszu.

Zobacz poniższy przykład

     let multiLineStringLiteral = """
    This is one of the best feature add in Swift 4
    It let’s you write “Double Quotes” without any escaping
    and new lines without need of “\n”
    """

print(multiLineStringLiteral)
Nareshkumar Nil
źródło
5

Szybki:

@connor jest prawidłową odpowiedzią, ale jeśli chcesz dodać wiersze w instrukcji drukowania, to czego szukasz \ni / lub \r, są to tak zwane sekwencje specjalne lub znaki ucieczki, jest to link do dokumentacji Apple na ten temat. .

Przykład:

print("First line\nSecond Line\rThirdLine...")
Juan Boero
źródło
6
Tego nie chce każdy. Chcemy mieć możliwość zawijania linii w kodzie źródłowym dla literałów łańcuchowych, niekoniecznie (koniecznie) podziału wierszy w renderowanym wyjściu . Myślę, że było to dość jasne w pierwotnym pytaniu. Ludzie z pozytywnymi wynikami oczywiście zrozumieli. Ludzie z ujemnymi wynikami oczywiście nie.
ArtOfWarfare
5
@ ArtOfWarfare to była odpowiedź, której szukałem, a ta strona była najlepszym rezultatem podczas wyszukiwania „nowego ciągu szybkiego wiersza”. Oczywiście nie jest to tak oczywiste, jak mówisz.
John R Perry
4

Dodając do odpowiedzi @Connor, należy również \ n. Oto poprawiony kod:

var text:String = "This is some text \n" +
                  "over multiple lines"
Pandurang Yachwad
źródło
3

Poniższy przykład przedstawia kontynuację wieloliniową, używając nawiasu jako prostego obejścia błędu Swift od wersji Xcode 6.2 Beta, w którym narzeka, że ​​wyrażenie jest zbyt złożone, aby można je było rozwiązać w rozsądnym czasie i rozważyć podzielenie go na mniejsze sztuk:

    .
    .
    .
    return String(format:"\n" +
                    ("    part1:    %d\n"    +
                     "    part2:    %d\n"    +
                     "    part3:  \"%@\"\n"  +
                     "    part4:  \"%@\"\n"  +
                     "    part5:  \"%@\"\n"  +
                     "    part6:  \"%@\"\n") +
                    ("    part7:  \"%@\"\n"  +
                     "    part8:  \"%@\"\n"  +
                     "    part9:  \"%@\"\n"  +
                     "    part10: \"%@\"\n"  +
                     "    part12: \"%@\"\n") +
                     "    part13:  %f\n"     +
                     "    part14:  %f\n\n",
                    part1, part2, part3, part4, part5, part6, part7, part8, 
                    part9, part10, part11, part12, part13, part14)
    .
    .
    .
jasne światło
źródło
0

Innym sposobem, jeśli chcesz użyć zmiennej łańcuchowej z pewnym predefiniowanym tekstem,

var textFieldData:String = "John"
myTextField.text = NSString(format: "Hello User, \n %@",textFieldData) as String
myTextField.numberOfLines = 0
Zoran777
źródło
0

Możesz użyć znaku Unicode do wprowadzenia lub \nzaimplementować je w swoim łańcuchu. Na przykład: \u{0085}.

hooman
źródło
0

Próba

var yourString = "first line \n second line \n third line"

W przypadku, gdy operator + nie jest odpowiedni

Danielle Cohen
źródło
0

Jednym z podejść jest ustawienie tekstu etykiety na atrybut atrybutText i zaktualizowanie zmiennej string w celu dołączenia kodu HTML do podziału wiersza (<br /> ).

Na przykład:

var text:String = "This is some text<br />over multiple lines"
label.attributedText = text

Wynik:

This is some text
over multiple lines

Mam nadzieję że to pomoże!

Ćwiek
źródło
Nie można przypisać Stringwartości (tekstu) do NSAttributedString?właściwości (label.attributeText).
Maxime Ashurov,
0

Oto fragment kodu dzielący ciąg znaków na n znaków rozdzielonych liniami:

//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {
    override func loadView() {

        let str = String(charsPerLine: 5, "Hello World!")
        print(str) // "Hello\n Worl\nd!\n"

    }
}

extension String {

    init(charsPerLine:Int, _ str:String){

        self = ""
        var idx = 0
        for char in str {
            self += "\(char)"
            idx = idx + 1
            if idx == charsPerLine {
                self += "\n"
                idx = 0
            }
        }

    }
}
Michael N.
źródło
-3

Wypróbowałem kilka sposobów, ale znalazłem jeszcze lepsze rozwiązanie: wystarczy użyć elementu „Widok tekstu”. Jego tekst wyświetla wiele linii automatycznie! Znaleziono tutaj: UITextField wiele linii

Oliver Ries
źródło
(po prostu wiesz, że opinie negatywne są prawdopodobnie dlatego, że pytanie dotyczyło formatowania kodu, a nie interfejsu użytkownika… i podanie próbki kodu w odpowiedzi prawdopodobnie uczyniłoby to bardziej widocznym)
benc