Nie byłem jeszcze w stanie dowiedzieć się, jak uzyskać podciąg String
w Swift:
var str = “Hello, playground”
func test(str: String) -> String {
return str.substringWithRange( /* What goes here? */ )
}
test (str)
Nie mogę utworzyć zasięgu w Swift. Autouzupełnianie na placu zabaw nie jest super pomocne - sugeruje to:
return str.substringWithRange(aRange: Range<String.Index>)
W Swift Standard Reference Library nie znalazłem nic, co by pomogło. Oto kolejne dzikie przypuszczenie:
return str.substringWithRange(Range(0, 1))
I to:
let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)
Widziałem inne odpowiedzi ( Finding index of character in Swift String ), które wydają się sugerować, że skoro String
jest to rodzaj mostu NSString
, „stare” metody powinny działać, ale nie jest jasne, jak - np. To też nie działa ( nie wydaje się być poprawną składnią):
let x = str.substringWithRange(NSMakeRange(0, 3))
Myśli?
Odpowiedzi:
Możesz użyć metody substringWithRange. Zajmuje początek i koniec String.Index.
Aby zmienić indeks początkowy i końcowy, użyj AdvancedBy (n).
Nadal możesz również używać metody NSString z NSRange, ale musisz się upewnić, że używasz NSString w następujący sposób:
Uwaga: jak wspomniano JanX2, ta druga metoda nie jest bezpieczna w przypadku ciągów znaków Unicode.
źródło
advance
oznacza, że musimy iterować całą drogę przez możliwie długi ciąg. Ale tworzenie NSRange i jawne używanie NSString jest niebezpieczne? Co zostało?Swift 2
Prosty
Szybki 3
Szybki 4
substring(to:)
isubstring(from:)
są przestarzałe wSwift 4
.źródło
UWAGA: @airspeedswift przedstawia kilka bardzo wnikliwych punktów na temat kompromisów tego podejścia, szczególnie ukrytych wpływów na wydajność. Łańcuchy nie są prostymi bestiami, a dotarcie do określonego indeksu może zająć czas O (n), co oznacza, że pętla korzystająca z indeksu dolnego może być O (n ^ 2). Zostałeś ostrzeżony.
Musisz tylko dodać nową
subscript
funkcję, która ma zasięg i używa,advancedBy()
aby przejść do żądanego miejsca:(To zdecydowanie powinno być częścią języka. Proszę o dupe rdar: // 17158813 )Dla zabawy możesz także dodać
+
operatora do indeksów:(Nie wiem jeszcze, czy ten powinien być częścią języka, czy nie.)
źródło
advance<T>(…)
wSwift
przestrzeni nazw.String.Index
. W tym przypadku nie tyle optymalizacja, co utrzymanie wszystkiego w prostocie. Konieczność żonglowania między int i String.Index wszędzie tam iz powrotem doprowadzi do bałaganu.String.Index
es), co często ma miejsce. Niż możesz sobie życzyć, aby wszystkie te metody obsługi ciągów pracowały zInt
s. I jesteś zmuszony przekonwertować to,String.Indexes
co prowadzi do bałaganu, o którym wspomniałeś.W chwili pisania tego artykułu żadne rozszerzenie nie jest w pełni kompatybilne z Swift 4.2 , więc oto jedno, które obejmuje wszystkie potrzeby, o których mogłem pomyśleć:
Następnie możesz użyć:
string.substring(from: 1, to: 7)
dostaje:ello,Wo
string.substring(to: 7)
dostaje:Hello,Wo
string.substring(from: 3)
dostaje:lo,World!
string.substring(from: 1, length: 4)
dostaje:ello
string.substring(length: 4, to: 7)
dostaje:o,Wo
Zaktualizowano
substring(from: Int?, length: Int)
do obsługi począwszy od zera.źródło
"Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)
daje nam:o😇😍😘😎📸📀💾∝ℵℶ
SWIFT 2.0
prosty:
SWIFT 3.0
SWIFT 4.0
Operacje na ciągach znaków zwracają instancję typu Podłańcuch zamiast Ciąg.
źródło
text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
Jest to o wiele prostsze niż dowolna z odpowiedzi tutaj, gdy znajdziesz właściwą składnię.
Chcę zabrać [i]
wynikiem będzie „ABCDEFGHI”, można również użyć parametru startIndex i endIndex
i tak dalej!
PS: Jak wskazano w uwagach, w swift 2, które są dostarczane z Xcode 7 i iOS9, wprowadzono pewne zmiany składniowe!
Proszę spojrzeć na tę stronę
źródło
advance(myString.endIndex, -1)
czasu zmiany składni Xcode 7 beta 6 namyString.endIndex.advancedBy(-1)
Na przykład, aby znaleźć imię (do pierwszej spacji) w moim pełnym imieniu:
start
iend
sąString.Index
tutaj typu i są używane do utworzeniaRange<String.Index>
i używane w akcesorium do indeksu dolnego (jeśli w oryginalnym ciągu znajduje się spacja).Trudno jest utworzyć
String.Index
bezpośrednio z pozycji liczby całkowitej stosowanej w poście otwierającym. Wynika to z faktu, że w moim imieniu każdy znak miałby jednakowy rozmiar w bajtach. Ale znaki używające specjalnych akcentów w innych językach mogły użyć jeszcze kilku bajtów (w zależności od zastosowanego kodowania). Do jakiego bajtu powinna się odnosić liczba całkowita?Możliwe jest utworzenie nowego
String.Index
od istniejącego przy użyciu metodsucc
ipred
który zadba o właściwą liczbę bajtów są pomijane, aby dostać się do następnego punktu kodu w kodowaniu. Jednak w tym przypadku łatwiej jest wyszukać indeks pierwszej spacji w ciągu, aby znaleźć indeks końcowy.źródło
Dla mnie to naprawdę interesująca część twojego pytania. String jest zmostkowane do NSString, więc większość metody NSString zrobić pracę bezpośrednio na sznurku. Możesz z nich korzystać swobodnie i bez zastanowienia. Na przykład działa to tak, jak się spodziewasz:
Ale, jak to często bywa, „mam moje mojo, ale po prostu nie działa na ciebie”. Właśnie zdarzyło Ci się wybrać jeden z rzadkich przypadków, w których istnieje równoległa metoda Swift o identycznej nazwie , aw takim przypadku metoda Swift przesłania metodę Objective-C. Zatem, kiedy mówisz
str.substringWithRange
, Swift myśli, że masz na myśli metodę Swift, a nie metodę NSString - i wtedy jesteś znienawidzony, ponieważ metoda Swift oczekujeRange<String.Index>
, a nie wiesz, jak zrobić jedną z nich.Najłatwiejszym sposobem jest powstrzymanie Swifta przed przesłaniem w ten sposób, przesyłając wprost:
Pamiętaj, że nie wymaga to żadnych znaczących dodatkowych prac. „Obsada” nie oznacza „konwersji”; ciąg jest efektywnie ciągiem NSS. Mówimy tylko Swiftowi, jak patrzeć na tę zmienną na potrzeby tego jednego wiersza kodu.
Naprawdę dziwną częścią tego wszystkiego jest to, że metoda Szybka, która powoduje wszystkie te kłopoty, jest nieudokumentowana. Nie mam pojęcia, gdzie to jest zdefiniowane; nie ma go w nagłówku NSString i nie ma go również w nagłówku Swift.
źródło
Range<String.Index>
, albo usunąć tę nieudokumentowaną metodę z naszej strony.W nowym użyciu Xcode 7.0
źródło
.advancedBy(0)
nie jest konieczne dla startIndex.Krótka odpowiedź brzmi: w Swift jest to naprawdę trudne. Mam przeczucie, że Apple wciąż ma wiele pracy nad metodami wygody dla takich rzeczy.
String.substringWithRange()
oczekujeRange<String.Index>
parametru i, o ile mogę stwierdzić, nie ma metody generatora dla tegoString.Index
typu. Można uzyskaćString.Index
wartości z powrotem zaString.startIndex
iaString.endIndex
i zadzwoń.succ()
lub.pred()
na nich, ale to szaleństwo.Co powiesz na rozszerzenie klasy String, które zajmuje dobre stare
Int
s?Aktualizacja: Swift beta 4 rozwiązuje poniższe problemy!
W obecnej wersji [w wersji beta 3 i wcześniejszych] nawet ciągi natywne Swift mają pewne problemy z obsługą znaków Unicode. Powyższa ikona psa działała, ale następujące nie:
Wynik:
źródło
NSString
zmusiło mnie do myślenia, że korzystam tylko zString
metod rodzimych Swift , ponieważ nie używałem żadnychmyString as NSString
wywołań.Możesz użyć tego rozszerzenia do ulepszenia
substringWithRange
Swift 2.3
Szybki 3
Stosowanie:
źródło
Przykładowy kod, jak uzyskać podciąg w Swift 2.0
(i) Podciąg z indeksu początkowego
Wejście:-
Wynik:-
(ii) Podciąg z określonego indeksu
Wejście:-
Wynik:-
Mam nadzieję, że ci to pomoże!
źródło
Proste rozwiązanie z niewielkim kodem.
Stwórz rozszerzenie, które obejmuje podstawowe subString, które mają prawie wszystkie inne języki:
Po prostu zadzwoń za pomocą
źródło
To działa na moim placu zabaw :)
źródło
advance
Zaktualizowano dla Xcode 7. Dodaje rozszerzenie String:
Posługiwać się:
Realizacja:
źródło
spróbuj tego na placu zabaw
da ci „ello, p”
Jednak gdy staje się to naprawdę interesujące, jeśli ustawisz ostatni indeks większy niż łańcuch na placu zabaw, pokaże wszystkie łańcuchy zdefiniowane po str: o
Range () wydaje się być funkcją ogólną, więc musi znać typ, z którym ma do czynienia.
Musisz również podać rzeczywisty ciąg, który jest zainteresowany placami zabaw, ponieważ wydaje się, że utrzymuje wszystkie żądła w sekwencji jeden po drugim z ich zmienną nazwą.
Więc
daje „ello, plac zabaw str Jestem następny ciąg str2 ”
działa, nawet jeśli str2 jest zdefiniowane za pomocą let
:)
źródło
Rob Napier udzielił już świetnej odpowiedzi za pomocą indeksu dolnego. Ale czułem jedną wadę, ponieważ nie ma możliwości sprawdzenia warunków poza granicami. Może to powodować awarię. Więc zmodyfikowałem rozszerzenie i oto jest
Wyjście poniżej
Dlatego sugeruję, aby zawsze sprawdzać, czy jest to dozwolone
źródło
W Swift3
Na przykład: zmienna „Duke James Thomas”, musimy uzyskać „James”.
źródło
Biorąc stronę Roba Napiera, opracowałem te wspólne rozszerzenia ciągów , z których dwa to:
Stosowanie:
źródło
Range
zamiastRange<String.Index>
dzięki wnioskowania typu.Oto jak uzyskać zakres z ciągu:
Kluczową kwestią jest to, że zamiast liczb całkowitych przekazujesz zakres wartości typu String.Index (właśnie to zwraca zaliczka).
Powodem, dla którego jest to konieczne, jest to, że ciągi w Swift nie mają losowego dostępu (z powodu zmiennej długości znaków Unicode). Ty też nie możesz
str[1]
. String.Index jest zaprojektowany do pracy z ich wewnętrzną strukturą.Możesz jednak utworzyć rozszerzenie z indeksem dolnym, który zrobi to za Ciebie, więc możesz po prostu przekazać zakres liczb całkowitych (patrz np . Odpowiedź Roba Napiera ).
źródło
Próbowałem wymyślić coś Pythonic.
Wszystkie indeksy tutaj są świetne, ale czasy, kiedy naprawdę potrzebuję czegoś prostego, zwykle są, gdy chcę liczyć od tyłu, np
string.endIndex.advancedBy(-1)
Obsługuje
nil
wartości, zarówno dla indeksu początkowego, jak i końcowego, gdzienil
oznaczałoby indeks o wartości 0 dla początku,string.characters.count
dla końca.EDYTOWAĆ
Bardziej eleganckie rozwiązanie:
źródło
Najpierw utwórz zakres, a następnie podciąg. Możesz użyć
fromIndex..<toIndex
składni w następujący sposób:źródło
oto przykład, aby szybko pobrać tylko identyfikator wideo .ie (6oL687G0Iso) z całego adresu URL
źródło
Pełną próbkę można zobaczyć tutaj
źródło
http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-swift/ pokazuje, że działa to dobrze:
źródło
Cóż, miałem ten sam problem i rozwiązałem go za pomocą funkcji „bridgeToObjectiveC ()”:
Należy zauważyć, że w tym przykładzie substringWithRange w połączeniu z NSMakeRange biorą udział w łańcuchu zaczynając od indeksu 6 (znak „W”) i kończąc na indeksie 6 + 6 pozycji do przodu (znak „!”)
Twoje zdrowie.
źródło
Możesz użyć dowolnej metody podciągów w rozszerzeniu Swift String, które napisałem https://bit.ly/JString .
źródło
Jeśli masz
NSRange
, pomost doNSString
działa płynnie. Na przykład robiłem trochę pracyUITextFieldDelegate
i szybko chciałem obliczyć nową wartość ciągu, gdy zapytano, czy powinna zastąpić zakres.źródło
Proste rozszerzenie dla
String
:źródło
Jeśli nie zależy Ci na wydajności ... jest to prawdopodobnie najbardziej zwięzłe rozwiązanie w Swift 4
Umożliwia zrobienie czegoś takiego:
źródło