Як ви використовуєте String.substringWithRange? (або як працюють дальність у Swift?)


266

Я ще не зміг зрозуміти, як отримати підрядку a Stringу Swift:

var str =Hello, playground”
func test(str: String) -> String {
 return str.substringWithRange( /* What goes here? */ )
}
test (str)

Я не в змозі створити діапазон у Свіфті. Автозаповнення на дитячому майданчику не дуже корисно - ось що пропонує:

return str.substringWithRange(aRange: Range<String.Index>)

Я не знайшов нічого в стандартній довідковій бібліотеці Swift, що допомагає. Ось ще одна дика здогадка:

return str.substringWithRange(Range(0, 1))

І це:

let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)

Я бачив інші відповіді ( Знаходження індексу символів у Swift String ), які, здається, підказують, що оскільки Stringце тип мосту NSString, "старі" методи повинні працювати, але незрозуміло, як - наприклад, це також не працює ( не здається правильним синтаксисом):

let x = str.substringWithRange(NSMakeRange(0, 3))

Думки?


Що ти маєш на увазі, коли кажеш, що останній приклад не працює? Це викликає помилку чи повертає несподіване значення?
67cherries

Будь ласка, dupe rdar: // 17158813 запит на підпис підписки openradar.appspot.com/radar?id=6373877630369792
Rob Napier

Відповіді:


259

Можна використовувати метод substringWithRange. Це займає початок і кінець String.Index.

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"

Щоб змінити індекс початку і кінця, використовуйте AdvancedBy (n).

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"

Ви також можете використовувати метод NSString з NSRange, але ви повинні переконатися, що ви використовуєте NSString так:

let myNSString = str as NSString
myNSString.substringWithRange(NSRange(location: 0, length: 3))

Примітка: як згадував JanX2, цей другий спосіб не є безпечним для рядків Unicode.


5
Так. Поки що я б продовжував моститися до NSString, коли це необхідно. Здається, струна Свіфта все ще незавершена
Коннор

14
Це не безпечно! Ви припускаєте, що індекси в String і NSString є взаємозамінними. Це НЕ так. Індекси в рядку посилаються на кодові точки Unicode, а індекси в NSString - на кодові одиниці UTF-16! Спробуйте це з емоджими.
JanX2

3
Зауважте, що індекси в рядку більше НЕ посилаються на кодові точки Unicode. Подумайте про них як на посилання на сприйняті користувачем символи.
JanX2

2
То яка правильна відповідь тут? Виклик advanceозначає, що ми повинні пройти повний шлях через можливо довгий рядок. Але формувати NSRange та використовувати NSString явно небезпечно? Що залишилося?
мат

1
Спасибі, m8. Цей перехід до Свіфта виглядає безладним через 4 роки, які роблять лише Objective-C.
Феліпе

162

Швидкий 2

Простий

let str = "My String"
let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)]
//"Strin"

Швидкий 3

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)

str[startIndex...endIndex]       // "Strin"
str.substring(to: startIndex)    // "My "
str.substring(from: startIndex)  // "String"

Швидкий 4

substring(to:)і substring(from:)застарілі в Росії Swift 4.

String(str[..<startIndex])    // "My "
String(str[startIndex...])    // "String"
String(str[startIndex...endIndex])    // "Strin"

2
ЦЕЙ. Настільки заплутаний, що вам доведеться знайти свій індекс, перш ніж його використовувати. Не маю ідеї, чому мені знадобилося так довго, але я дякую за ваш внесок у людський рід.
Warpzit

1
У швидких 4 операціях з підрядкою повертається екземпляр типу Substring замість String. Потрібно перетворити результат у рядок для довготривалого зберігання. нехай newString = String (substring)
phnmnn

43

ПРИМІТКА: @airspeedswift робить дуже проникливі моменти щодо компромісів цього підходу, зокрема прихованих наслідків щодо продуктивності. Рядки не є простими звірами, і потрапляння на певний індекс може зайняти O (n) час, а це означає, що цикл, який використовує індекс, може бути O (n ^ 2). Вас попередили

Вам просто потрібно додати нову subscriptфункцію, яка займає діапазон і використовує advancedBy()для переходу туди, куди ви хочете:

import Foundation

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex = self.startIndex.advancedBy(r.startIndex)
            let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

var s = "Hello, playground"

println(s[0...5]) // ==> "Hello,"
println(s[0..<5]) // ==> "Hello"

(Це обов'язково має бути частиною мови. Будь ласка, dupe rdar: // 17158813 )

Для розваги можна також додати +оператора до індексів:

func +<T: ForwardIndex>(var index: T, var count: Int) -> T {
  for (; count > 0; --count) {
    index = index.succ()
  }
  return index
}

s.substringWithRange(s.startIndex+2 .. s.startIndex+5)

(Я ще не знаю, чи ця мова повинна бути частиною мови чи ні.)


2
Напевно, ми маємо працювати з String.Index замість цілих індексів максимально з міркувань продуктивності. Кожне перетворення з цілого індексу в String.Index потрібно обробити рядок для пошуку.
JanX2

11
@AndrewDunn Це не передчасна оптимізація. Кожне перетворення з цілого індексу в String.Index - це O (n), а не O (1)! Прочитайте коментарі advance<T>(…)до Swiftпростору імен.
JanX2

1
Вся реалізація String виконується за допомогою String.Index. В даному випадку це не стільки оптимізація, скільки утримання все прямо. Переміщення між int і String.Index скрізь і назад всюди призведе до безладу.
чакрит

@chakrit Тільки якщо індекси, які вам потрібно використовувати, це вже не цілі числа (а не String.Indexes), що часто буває. Тоді ви просто можете побажати, щоб усі ті методи обробці рядків працювали з Ints. І ви змушені конвертувати це, String.Indexesщо призводить до згаданого вами безладу.
Расто

Зацікавлений читач повинен ознайомитись з ExSwift github.com/pNre/ExSwift
AsTeR

42

На той момент, коли я пишу, жодне розширення не є ідеально сумісним Swift 4.2 , тож ось одне, яке охоплює всі потреби, про які я міг придумати:

extension String {
    func substring(from: Int?, to: Int?) -> String {
        if let start = from {
            guard start < self.count else {
                return ""
            }
        }

        if let end = to {
            guard end >= 0 else {
                return ""
            }
        }

        if let start = from, let end = to {
            guard end - start >= 0 else {
                return ""
            }
        }

        let startIndex: String.Index
        if let start = from, start >= 0 {
            startIndex = self.index(self.startIndex, offsetBy: start)
        } else {
            startIndex = self.startIndex
        }

        let endIndex: String.Index
        if let end = to, end >= 0, end < self.count {
            endIndex = self.index(self.startIndex, offsetBy: end + 1)
        } else {
            endIndex = self.endIndex
        }

        return String(self[startIndex ..< endIndex])
    }

    func substring(from: Int) -> String {
        return self.substring(from: from, to: nil)
    }

    func substring(to: Int) -> String {
        return self.substring(from: nil, to: to)
    }

    func substring(from: Int?, length: Int) -> String {
        guard length > 0 else {
            return ""
        }

        let end: Int
        if let start = from, start > 0 {
            end = start + length - 1
        } else {
            end = length - 1
        }

        return self.substring(from: from, to: end)
    }

    func substring(length: Int, to: Int?) -> String {
        guard let end = to, end > 0, length > 0 else {
            return ""
        }

        let start: Int
        if let end = to, end - length > 0 {
            start = end - length + 1
        } else {
            start = 0
        }

        return self.substring(from: start, to: to)
    }
}

І тоді ви можете використовувати:

let string = "Hello,World!"

string.substring(from: 1, to: 7)отримує тебе: ello,Wo

string.substring(to: 7)отримує тебе: Hello,Wo

string.substring(from: 3)отримує тебе: lo,World!

string.substring(from: 1, length: 4)отримує тебе: ello

string.substring(length: 4, to: 7)отримує тебе: o,Wo

Оновлено substring(from: Int?, length: Int)для підтримки, починаючи з нуля.


Як це поводиться з емоджі та розширеними кластерами графем? (Я повинен це перевірити сам, але наразі це не зручно.)
Сурагч,

2
@Suragch Це справляється з "Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)нами добре: дає нам:o😇😍😘😎📸📀💾∝ℵℶ
перезимував

Однак вони схожі на нормальних персонажів. Спробуйте використовувати емоджи, як 👩‍👩‍👧‍👦 або 🇨🇦🇺🇸🇲🇽
Supuhstar

31

SWIFT 2.0

просто:

let myString = "full text container"
let substring = myString[myString.startIndex..<myString.startIndex.advancedBy(3)] // prints: ful

SWIFT 3.0

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

SWIFT 4.0

Операції з підрядкою повертають екземпляр типу Substring замість String.

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

// Convert the result to a String for long-term storage.
let newString = String(substring)

4
Більше не сумісний зі Swift 3 станом на Xcode 8 beta 6, на жаль
Ben Morrow

1
Працює для мене. Xcode 8, Swift 3. Не бета-версія на Mac OS Sierra. text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
Хосе Рамірес

18

Це набагато простіше, ніж будь-яка відповідь тут, як тільки ви знайдете правильний синтаксис.

Я хочу забрати [і]

let myString = "[ABCDEFGHI]"
let startIndex = advance(myString.startIndex, 1) //advance as much as you like
let endIndex = advance(myString.endIndex, -1)
let range = startIndex..<endIndex
let myNewString = myString.substringWithRange( range )

Результатом буде "ABCDEFGHI", також можуть бути використані startIndex і endIndex

let mySubString = myString.substringFromIndex(startIndex)

і так далі!

PS: Як зазначено у зауваженні, у swift 2 є деякі зміни синтаксису, які поставляються з xcode 7 та iOS9!

Будь ласка, подивіться на цю сторінку


Так, у мене були ті ж самі проблеми з налагоджувачем, що не показував правильний рядок кілька разів?
користувач1700737

у мене є такий рядок / дата (147410000000) /. Як я можу отримати значення замість зазначення індексу. Мені потрібно отримати значення, використовуючи rangeOfString ("(") та rangeOfString (")"). Результат повинен бути 147410000000. Мога, я можу це отримати
iPhone Гай

Це не так складно: var str = "/ Дата (147410000000) /." var range = str.rangeOfString ("(")! endIndex .. <str.rangeOfString (")")! startIndex нехай myNewString = str.substringWithRange (range)
користувач1700737

4
оскільки advance(myString.endIndex, -1)синтаксис Xcode 7 бета-6 змінився наmyString.endIndex.advancedBy(-1)
l --marc l

16

Наприклад, щоб знайти своє ім’я (до першого пробілу) у моєму повному імені:

let name = "Joris Kluivers"

let start = name.startIndex
let end = find(name, " ")

if end {
    let firstName = name[start..end!]
} else {
    // no space found
}

startі endвони є типом String.Indexтут і використовуються для створення Range<String.Index>і використовуються в аксесуарі підпису (якщо пробіл взагалі знайдено в початковій рядку).

Важко створити String.Indexбезпосередньо з цілої позиції, як використовується у вступному пості. Це тому, що в моєму імені кожен символ був би однакового розміру в байтах. Але символи, які використовують спеціальні наголоси на інших мовах, могли використати ще кілька байтів (залежно від використовуваного кодування). То до якого байта має відноситися ціле число?

Можна створити новий String.Indexз існуючого з використанням методів succі predякий буде переконатися , що правильне кількість байт, пропускається , щоб дістатися до наступного пункту коду в кодуванні. Однак у цьому випадку простіше шукати індекс першого пробілу в рядку, щоб знайти кінцевий індекс.


16

Оскільки String - це тип мосту для NSString, "старі" методи повинні працювати, але незрозуміло, як - наприклад, це також не працює (не здається, що це синтаксис):

 let x = str.substringWithRange(NSMakeRange(0, 3))

Для мене це справді цікава частина вашого запитання. Рядок є містком NSString, тому більшість методів NSString зробити роботу безпосередньо на String. Ви можете використовувати їх вільно і не замислюючись. Наприклад, наприклад, це працює так, як ви очікуєте:

// delete all spaces from Swift String stateName
stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"")

Але, як це часто буває, "я працюю над моджо, але це просто не працює на вас". Щойно ви вибрали один з рідкісних випадків, коли існує паралельна однаково ім'я методу Swift , а в такому випадку метод Swift затьмарює метод Objective-C. Таким чином, коли ви говорите str.substringWithRange, Swift думає, що ви маєте на увазі метод Swift, а не метод NSString, - і тоді ви шлангуєте, тому що метод Swift очікує a Range<String.Index>, і ви не знаєте, як зробити один із них.

Найпростіший вихід - зупинити Swift від такого затьмарення, чітко відкидаючи:

let x = (str as NSString).substringWithRange(NSMakeRange(0, 3))

Зауважте, що тут не задіяно жодної значної додаткової роботи. "Cast" не означає "конвертувати"; Рядок - це фактично NSString. Ми просто розповідаємо Swift, як дивитися на цю змінну для цілей цього одного рядка коду.

Дійсно дивна частина всього цього полягає в тому, що метод Свіфта, який викликає всю цю неприємність, є недокументованим. Я не маю уявлення, де це визначено; це не в заголовку NSString, а також у заголовку Swift.


Однак я пропоную подати помилку. Яблуко повинно "рибалити або нарізати наживку" - або дати нам спосіб побудувати Range<String.Index>, або позбутися цього недокументованого методу.
матовий

Чорт - це корисно. Незважаючи на те, що йдеться в документації, я не зрозумів, що пішло не так, поки я не прочитав це. Зараз відсортовано :)
Джон М

13

У новому використанні Xcode 7.0

//: Playground - noun: a place where people can play

import UIKit

var name = "How do you use String.substringWithRange?"
let range = name.startIndex.advancedBy(0)..<name.startIndex.advancedBy(10)
name.substringWithRange(range)

//OUT:

введіть тут опис зображення


2
.advancedBy(0) не потрібен для startIndex.
Мат0

12

Коротка відповідь полягає в тому, що зараз у Свіфта це дуже важко. Моя думка полягає в тому, що перед Apple ще багато роботи над зручністю для таких речей.

String.substringWithRange()очікує Range<String.Index>параметр, і наскільки я можу сказати, немає методу генератора для String.Indexтипу. Ви можете отримати String.Indexзначення назад від aString.startIndexі aString.endIndexі зателефонувати .succ()або.pred() на них, але це безумство.

Як щодо розширення класу String, яке займає добрі старі Ints?

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let subStart = advance(self.startIndex, r.startIndex, self.endIndex)
            let subEnd = advance(subStart, r.endIndex - r.startIndex, self.endIndex)
            return self.substringWithRange(Range(start: subStart, end: subEnd))
        }
    }
    func substring(from: Int) -> String {
        let end = countElements(self)
        return self[from..<end]
    }
    func substring(from: Int, length: Int) -> String {
        let end = from + length
        return self[from..<end]
    }
}

let mobyDick = "Call me Ishmael."
println(mobyDick[8...14])             // Ishmael

let dogString = "This 🐶's name is Patch."
println(dogString[5..<6])               // 🐶
println(dogString[5...5])              // 🐶
println(dogString.substring(5))        // 🐶's name is Patch.
println(dogString.substring(5, length: 1))   // 🐶

Оновлення: Swift beta 4 вирішує проблеми нижче!

Як і раніше [у бета-версії 3 та новіших версій], навіть у рідних рядків Swift є деякі проблеми з обробкою символів Unicode. Піктограма собаки працювала вище, але наступне:

let harderString = "1:1️⃣"
for character in harderString {
    println(character)
}

Вихід:

1
:
1
️
⃣

1
Як не дивно, ядра класів Swift просто не вистачає багатьох основних функцій. Я не можу подумати, що Apple хоче, щоб ми постійно посилалися на класи Foundation для виконання простих завдань.
bluedevil2k

1
Повністю. Майте на увазі, що Свіфт в основному був розроблений у темний час доби, і всі мають різні визначення поняття "прості завдання" - Я думаю, що ми бачимо певну швидку ітерацію з цих питань.
Нейт Кук

@ JanX2 - Дякую, ви абсолютно праві. Безпроблемне з’єднання з NSStringмені змусило мене думати, що я використовую лише Stringметоди " Швидкого" , оскільки я не використовував жодних myString as NSStringдзвінків.
Нейт Кук

Є декілька помилок Unicode в обробці рядків Swift і зараз: див. Мою примітку наприкінці.
Нейт Кук

@NateCook Чи можете ви, будь ласка, подати радар для цього питання?
JanX2

11

Ви можете використовувати ці розширення для покращення substringWithRange

Швидкий 2.3

extension String
{   
    func substringWithRange(start: Int, end: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if end < 0 || end > self.characters.count
        {
            print("end index \(end) out of bounds")
            return ""
        }
        let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
        return self.substringWithRange(range)
    }

    func substringWithRange(start: Int, location: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if location < 0 || start + location > self.characters.count
        {
            print("end index \(start + location) out of bounds")
            return ""
        }
        let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
        return self.substringWithRange(range)
    }
}

Швидкий 3

extension String
{
    func substring(start: Int, end: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if end < 0 || end > self.characters.count
        {
            print("end index \(end) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: end)
        let range = startIndex..<endIndex

        return self.substring(with: range)
    }

    func substring(start: Int, location: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if location < 0 || start + location > self.characters.count
        {
            print("end index \(start + location) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
        let range = startIndex..<endIndex

        return self.substring(with: range)
    }
}

Використання:

let str = "Hello, playground"

let substring1 = str.substringWithRange(0, end: 5) //Hello
let substring2 = str.substringWithRange(7, location: 10) //playground

7

Приклад коду, як отримати підрядку в Swift 2.0

(i) Підряд з початкового індексу

Вхід: -

var str = "Swift is very powerful language!"
print(str)

str = str.substringToIndex(str.startIndex.advancedBy(5))
print(str)

Вихід: -

Swift is very powerful language!
Swift

(ii) Підстроковим рядком з певного індексу

Вхід: -

var str = "Swift is very powerful language!"
print(str)

str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2))
print(str)

Вихід: -

Swift is very powerful language!
is

Сподіваюся, це допоможе тобі!


7

Просте рішення з невеликим кодом.

Зробіть розширення, що включає в себе базову підстрокову структуру, яку мають майже всі інші мови:

extension String {
    func subString(start: Int, end: Int) -> String {
        let startIndex = self.index(self.startIndex, offsetBy: start)
        let endIndex = self.index(startIndex, offsetBy: end)

        let finalString = self.substring(from: startIndex)
        return finalString.substring(to: endIndex)
    }
}

Просто подзвоніть це за допомогою

someString.subString(start: 0, end: 6)

1
Параметр 'end' насправді означає довжину, тому я думаю, що його слід перейменувати на це.
Йован Йовановський

Я думаю, що використання довжини досить заплутано. Насправді це "кінець" того, де ви хочете, щоб перебувала підзарядка, а не фактична довжина результату "SubStrings".
Олівер Діксон

6

Це працює на моєму майданчику :)

String(seq: Array(str)[2...4])

Насправді це ефективніше, ніж дзвонитиadvance
Ерік Егнер

2
У моєму ігровому майданчику Xcode 7 (Swift 2) це не працює, але це робить ... 'var str = "Привіт, майданчик" "String (Array (str.characters) [7]) //" p "String (Array ( str.characters) [7 ... 10]) // "play" String (Array (str.characters) [7 .. <10]) // "pla"
Вінс О'Салліван

6

Оновлено для Xcode 7. Додає розширення String:

Використання:

var chuck: String = "Hello Chuck Norris"
chuck[6...11] // => Chuck

Впровадження:

extension String {

    /**
     Subscript to allow for quick String substrings ["Hello"][0...1] = "He"
     */
    subscript (r: Range<Int>) -> String {
        get {
            let start = self.startIndex.advancedBy(r.startIndex)
            let end = self.startIndex.advancedBy(r.endIndex - 1)
            return self.substringWithRange(start..<end)
        }
    }

}

4

спробуйте це на дитячому майданчику

var str:String = "Hello, playground"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8))

це дасть вам "Елло, р"

Однак, коли це стає справді цікавим, це те, що якщо ви зробите останній індекс більшим за рядок на ігровому майданчику, він покаже будь-які рядки, які ви визначили після str: o

Range (), здається, є загальною функцією, тому йому потрібно знати тип, з яким він має справу.

Ви також повинні надати йому фактичну нитку, яка зацікавлена ​​у вас на ігрових майданчиках, оскільки, здається, утримуються всі струни в послідовності одна за одною з назвою змінної згодом.

Так

var str:String = "Hello, playground"

var str2:String = "I'm the next string"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,49))

дає «Елло, майданчик str Я я наступний рядок str2 »

працює, навіть якщо str2 визначено let

:)


Я погоджуюсь, що він є багатослівним порівняно з Objective-C, проте все це відповідає одному рядку, який є бонусом.
Пітер Робертс

Добре, все ще є один рядок, який насправді виводить підрядку з огляду на діапазон, який ви обчислили. Мені подобаються деякі інші рішення, які створюють розширення класу String, використовуючи вашу логіку, але в розширенні. Це в кінцевому підсумку рішення, з яким я пішов.
Родерік Кемпбелл

Вони виправили помилку, куди ви можете вийти за межі кінця рядка. Тепер ви можете лише встановити значення до str.endIndex
Пітер Робертс

4

Роб Неп'є вже дав приголомшливу відповідь, використовуючи підпис. Але я відчув один недолік у тому, що немає перевірки на невиконання умов. Це може призвести до краху. Тож я змінив розширення і ось воно

extension String {
    subscript (r: Range<Int>) -> String? { //Optional String as return value
        get {
            let stringCount = self.characters.count as Int
            //Check for out of boundary condition
            if (stringCount < r.endIndex) || (stringCount < r.startIndex){
                return nil
            }
            let startIndex = self.startIndex.advancedBy(r.startIndex)

            let endIndex = self.startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

Вихід нижче

var str2 = "Hello, World"

var str3 = str2[0...5]
//Hello,
var str4 = str2[0..<5]
//Hello
var str5 = str2[0..<15]
//nil

Тому я пропоную завжди перевіряти, чи дозволяю

if let string = str[0...5]
{
    //Manipulate your string safely
}

У вас там помилка - endIndex повинен бути запущений startIndex лише ендіндекс, а не відстань між показниками.
Авіад Бен Дов

3

В Swift3

Наприклад: змінна "Герцог Джеймс Томас", нам потрібно отримати "Джеймс".

let name = "Duke James Thomas"
let range: Range<String.Index> = name.range(of:"James")!
let lastrange: Range<String.Index> = img.range(of:"Thomas")!
var middlename = name[range.lowerBound..<lstrange.lowerBound]
print (middlename)

2

Зробивши сторінку від Rob Napier, я розробив ці поширені розширення для рядків , два з яких:

subscript (r: Range<Int>) -> String
{
    get {
        let startIndex = advance(self.startIndex, r.startIndex)
        let endIndex = advance(self.startIndex, r.endIndex - 1)

        return self[Range(start: startIndex, end: endIndex)]
    }
}

func subString(startIndex: Int, length: Int) -> String
{
    var start = advance(self.startIndex, startIndex)
    var end = advance(self.startIndex, startIndex + length)
    return self.substringWithRange(Range<String.Index>(start: start, end: end))
}

Використання:

"Awesome"[3...7] //"some"
"Awesome".subString(3, length: 4) //"some"

Ви можете використовувати Rangeзамість цього, Range<String.Index>завдяки виводу типу.
Дан Розенстарк

2

Ось як ви отримуєте діапазон від рядка:

var str = "Hello, playground"

let startIndex = advance(str.startIndex, 1)
let endIndex = advance(startIndex, 8)
let range = startIndex..<endIndex
let substr = str[range] //"ello, pl"

Ключовим моментом є те, що ви передаєте діапазон значень типу String.Index (це те, що повертається заздалегідь) замість цілих чисел.

Причина, чому це необхідно, полягає в тому, що рядки в Swift не мають випадкового доступу (в основному через змінну довжину символів Unicode). Ви також не можете робити str[1]. String.Index призначений для роботи зі своєю внутрішньою структурою.

Ви можете створити розширення за допомогою індекса, але це робить для вас, так що ви можете просто передати ряд цілих чисел (див., Наприклад , відповідь Роб Неп'є ).


2

Я намагався придумати щось піфонічне.

Усі підписки тут чудові, але час, коли мені справді потрібно щось просте, зазвичай, коли я хочу рахувати ззаду, наприклад string.endIndex.advancedBy(-1)

Він підтримує nilзначення, як для початкового, так і для кінцевого індексів, де nilозначав би індекс у 0 для початку, string.characters.countдля кінця.

extension String {
    var subString: (Int?) -> (Int?) -> String {
        return { (start) in
            { (end) in
                let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0)
                let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count)

                return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex)
            }
        }
    }
}

let dog = "Dog‼🐶"
print(dog.subString(nil)(-1)) // Dog!!

EDIT

Більш елегантне рішення:

public extension String {
    struct Substring {
        var start: Int?
        var string: String

        public subscript(end: Int?) -> String {
            let startIndex = start ?? 0 < 0 ? string.endIndex.advancedBy(start!) : string.startIndex.advancedBy(start ?? 0)
            let endIndex = end ?? string.characters.count < 0 ? string.endIndex.advancedBy(end!) : string.startIndex.advancedBy(end ?? string.characters.count)

            return startIndex > endIndex ? "" : string.substringWithRange(startIndex ..< endIndex)
        }
    }

    public subscript(start: Int?) -> Substring {
        return Substring(start: start, string: self)
    }
}

let dog = "Dog‼🐶"
print(dog[nil][-1]) // Dog!!

1

Спочатку створіть діапазон, потім підрядку. Ви можете використовувати fromIndex..<toIndexсинтаксис так:

let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string
let substring = fullString.substringWithRange(range)

1

ось приклад, як швидко отримати лише відео-ідентифікатор .ie (6oL687G0Iso) з усієї URL-адреси

let str = "https://www.youtube.com/watch?v=6oL687G0Iso&list=PLKmzL8Ib1gsT-5LN3V2h2H14wyBZTyvVL&index=2"
var arrSaprate = str.componentsSeparatedByString("v=")
let start = arrSaprate[1]
let rangeOfID = Range(start: start.startIndex,end:start.startIndex.advancedBy(11))
let substring = start[rangeOfID]
print(substring)

1
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)

Повний зразок ви можете побачити тут



0

Ну, у мене була та сама проблема, і я вирішив функцію "bridgeToObjectiveC ()":

var helloworld = "Hello World!"
var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6))
println("\(world)") // should print World!

Зверніть увагу, що у прикладі substringWithRange спільно з NSMakeRange приймають частину рядка, починаючи з індексу 6 (символ "W") і закінчуючи на позиції індексу 6 + 6 попереду (символ "!")

Ура.


Я ненавиджу це, але це єдине, що, здається, працює для мене у бета-версії 4.
Родерік Кемпбелл

0

Ви можете використовувати будь-який із методів підрядки у розширенні Swift String, про яке я писав https://bit.ly/JString .

var string = "hello"
var sub = string.substringFrom(3) // or string[3...5]
println(sub)// "lo"

0

Якщо у вас є NSRange, мостика NSStringпрацює безперебійно. Наприклад, я робив певну роботу UITextFieldDelegateі мені швидко хотілося обчислити нове значення рядка, коли він запитав, чи слід замінити діапазон.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    println("Got new string: ", newString)
}

0

Просте розширення для String:

extension String {

    func substringToIndex(index: Int) -> String {
        return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))]
    }
}

0

Якщо ви не дбаєте про продуктивність ... це, мабуть, найбільш стисле рішення у Swift 4

extension String {
    subscript(range: CountableClosedRange<Int>) -> String {
        return enumerated().filter{$0.offset >= range.first! && $0.offset < range.last!}
            .reduce(""){$0 + String($1.element)}
    }
}

Це дає змогу зробити щось подібне:

let myStr = "abcd"
myStr[0..<2] // produces "ab"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.