Czas przyznać się do porażki ...
W Objective-C mógłbym użyć czegoś takiego:
NSString* str = @"abcdefghi";
[str rangeOfString:@"c"].location; // 2
W Swift widzę coś podobnego:
var str = "abcdefghi"
str.rangeOfString("c").startIndex
... ale to po prostu daje mi opcję String.Index
, której mogę użyć, aby zapisać indeks z powrotem do oryginalnego ciągu, ale nie wyodrębnić lokalizacji.
FWIW, który String.Index
ma prywatny ivar o nazwie _position
o poprawnej wartości. Po prostu nie widzę, jak to się dzieje
Wiem, że sam mógłbym łatwo dodać to do String. Jestem ciekaw, czego brakuje mi w tym nowym interfejsie API.
Odpowiedzi:
Nie jesteś jedynym, który nie mógł znaleźć rozwiązania.
String
nie implementujeRandomAccessIndexType
. Prawdopodobnie dlatego, że umożliwiają znaki o różnych długościach bajtów. Dlatego musimy użyćstring.characters.count
(count
lubcountElements
w Swift 1.x), aby uzyskać liczbę znaków. Dotyczy to również pozycji. Jest_position
to prawdopodobnie indeks do surowej tablicy bajtów i nie chcą tego ujawniać. MaString.Index
to na celu ochronę nas przed dostępem do bajtów w środku znaków.Oznacza to, że każdy indeks, który otrzymujesz, musi zostać utworzony z
String.startIndex
lubString.endIndex
(String.Index
implementujeBidirectionalIndexType
). Wszelkie inne indeksy można tworzyć za pomocąsuccessor
lubpredecessor
metod.Teraz, aby pomóc nam z indeksami, istnieje zestaw metod (funkcje w Swift 1.x):
Swift 4.x
Swift 3.0
Swift 2.x
Swift 1.x
Praca z
String.Index
jest uciążliwa, ale używanie otoki do indeksowania według liczb całkowitych (patrz https://stackoverflow.com/a/25152652/669586 ) jest niebezpieczne, ponieważ ukrywa nieefektywność rzeczywistego indeksowania.Należy pamiętać, że implementacja szybkiego indeksowania ma problem polegający na tym, że indeksy / zakresy utworzone dla jednego ciągu nie mogą być niezawodnie użyte dla innego ciągu , na przykład:
Swift 2.x
Swift 1.x
źródło
range
wvar range = text.rangeOfString("b")
Collection
matypealias IndexType
. W przypadku tablic jest on zdefiniowany jakoInt
,String
ponieważ jest zdefiniowany jakoString.Index
. Zarówno tablice, jak i łańcuchy mogą również używać zakresów (do tworzenia podtablic i podciągów). Zakres jest specjalnym typemRange<T>
. W przypadku ciągów znaków toRange<String.Index>
tabliceRange<Int>
.Swift 2.0
,distance(text.startIndex, range.startIndex)
staje siętext.startIndex.distanceTo(range.startIndex)
String
, dokładnie tak jakNSString
w Foundation ma metodę o nazwiehasPrefix(_:)
.Swift 3.0 sprawia, że jest to bardziej szczegółowe:
Rozbudowa:
W Swift 2.0 stało się to łatwiejsze:
Rozbudowa:
Implementacja Swift 1.x:
Dla czystego rozwiązania Swift można użyć:
Jako rozszerzenie do
String
:źródło
źródło
Znalazłem to rozwiązanie dla swift2:
źródło
Swift 5.0
Swift 4.0
źródło
Nie jestem pewien, jak wyodrębnić pozycję z String.Index, ale jeśli chcesz oprzeć się o niektóre frameworki Objective-C, możesz połączyć się z celem-c i zrobić to tak, jak kiedyś.
Wygląda na to, że niektóre metody NSString nie zostały (a może nie zostaną) przeniesione do String. Zawiera również przychodzi na myśl.
źródło
bridgeToObjectiveC()
wywołanie nie jest potrzebne. Mój problem wydaje się objawiać tylko podczas wywoływaniarangeOfString
wcześniej istniejącego Swift String. Wygląda na problem z interfejsem API ...Oto czyste rozszerzenie String, które odpowiada na pytanie:
Swift 3:
Swift 2.2:
źródło
Możesz także znaleźć indeksy znaku w jednym ciągu, takim jak ten,
Co daje wynik w [String.Distance] tj. [Int], jak
źródło
Jeśli chcesz użyć znanego narzędzia NSString, możesz to wyraźnie zadeklarować:
Nie jestem jeszcze pewien, jak to zrobić w Swift.
źródło
Jeśli chcesz poznać stanowisko o charakterze w ciąg jako int wykorzystania wartości to:
źródło
value of type 'Range<String.Index>?' has no member 'location'
.Wiem, że jest stary i odpowiedź została zaakceptowana, ale indeks ciągu można znaleźć w kilku wierszach kodu, używając:
Kilka innych świetnych informacji na temat łańcuchów Swift tutaj Strings in Swift
źródło
find
nie jest dostępny w Swift 3To zadziałało dla mnie
to też działało
źródło
var str = "abcdef"; str.rangeOfString("c").location
zgłasza błąd związany z brakiem elementu String.Index o nazwie lokalizacja ...Typ zmiennej String w Swift zawiera inne funkcje w porównaniu do NSString w Objective-C. I jak wspomniał Sulthan,
Możesz sprowadzić zmienną typu String do NSString (jest to poprawne w Swift). Umożliwi to dostęp do funkcji w NSString.
źródło
Jeśli się nad tym zastanowisz, tak naprawdę nie potrzebujesz dokładnej wersji Int lokalizacji. Range, a nawet String.Index wystarczy, aby w razie potrzeby ponownie pobrać podciąg:
źródło
Najprostszym sposobem jest:
W Swift 3 :
źródło
String jest typem mostka dla NSString, więc dodaj
do szybkiego pliku i użyj wszystkich „starych” metod.
źródło
Pod względem myślenia można to nazwać INWERSJĄ. Odkrywasz, że świat jest okrągły zamiast płaskiego. „Naprawdę nie musisz znać INDEKSU postaci, aby coś z tym zrobić”. A jako programista C też ciężko mi było to wziąć! Twój wiersz „let index = letters.characters.indexOf („ c ”)!” sam w sobie wystarcza. Na przykład, aby usunąć c, którego możesz użyć ... (wklej na placu zabaw)
Jeśli jednak potrzebujesz indeksu, musisz zwrócić rzeczywisty INDEKS, a nie wartość Int, ponieważ wartość Int wymagałaby dodatkowych kroków w celu praktycznego zastosowania. Te rozszerzenia zwracają indeks, liczbę określonych znaków i zakres, który pokaże ten kod wtyczki placu zabaw.
źródło
Kompletne rozwiązanie Swift 4:
OffsetIndexableCollection (ciąg znaków przy użyciu indeksu Int)
https://github.com/frogcjn/OffsetIndexableCollection-String-Int-Indexable-
źródło
rozszerzenie String {
}
źródło
Szybki 5
Znajdź indeks podciągów
Znajdź indeks postaci
źródło
Jeśli szukasz łatwego sposobu uzyskania indeksu postaci lub ciągu, sprawdź tę bibliotekę http://www.dollarswift.org/#indexof-char-character-int
Możesz pobrać indexOf z łańcucha używając również innego łańcucha lub wzorca wyrażenia regularnego
źródło
Aby uzyskać indeks podłańcucha w ciągu za pomocą Swift 2:
źródło
W szybkim 2.0
źródło
źródło
Gram z podążaniem
dopóki nie zrozumiem, że pod warunkiem, że teraz jest to tylko tablica postaci
i z
źródło
Jeśli potrzebujesz tylko indeksu znaku, najprostszym i najszybszym rozwiązaniem (jak już wskazał Pascal) jest:
źródło
Jeśli chodzi o przekształcenie
String.Index
w anInt
, to rozszerzenie działa dla mnie:Przykładowe użycie związane z tym pytaniem:
Ważny:
Jak widać, grupuje rozszerzone klastry grafem i łączy postacie inaczej niż
String.Index
. Oczywiście właśnie dlategoString.Index
. Należy pamiętać, że ta metoda traktuje klastry jako znaki pojedyncze, co jest bliższe do poprawienia. Jeśli Twoim celem jest podzielenie łańcucha według punktu kodowego Unicode, nie jest to rozwiązanie dla Ciebie.źródło
W Swift 2.0 następująca funkcja zwraca podłańcuch przed danym znakiem.
źródło
Możesz znaleźć numer indeksu znaku w ciągu:
źródło
Z mojej perspektywy, lepszy sposób na poznanie samej logiki jest poniżej
źródło