Как вы используете String.substringWithRange? (или как работает Ranges в Swift?)

261

Мне еще не удалось выяснить, как получить подстроку String в Swift:

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

Я не могу создать Range в Swift. Автозаполнение на игровой площадке не очень полезно - вот что он предлагает:

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))

Мысли?

  • 0
    Что вы имеете в виду, когда говорите, что последний пример не работает? Это вызывает ошибку или возвращает неожиданное значение?
  • 0
    Пожалуйста, дублируйте rdar: // 17158813, запрашивая запись в нотации openradar.appspot.com/radar?id=6373877630369792
Теги:

33 ответа

261
Лучший ответ

Вы можете использовать метод 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.

  • 0
    Интересно. Я удивлен, что он принимает только Range <String.Index>, я бы ожидал Range <Int>.
  • 5
    Да уж. Пока я буду продолжать соединяться с NSString, когда это необходимо. Кажется, строка Свифта все еще не завершена
Показать ещё 11 комментариев
151

Swift 2

Простой

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

Swift 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"

Swift 4

substring(to:) и substring(from:) устарели в Swift 4.

String(str[..<startIndex])    // "My "
String(str[startIndex...])    // "String"
String(str[startIndex...endIndex])    // "Strin"
  • 2
    ЭТОТ. Так запутанно, что вам нужно найти свой индекс, прежде чем вы сможете его использовать. Не знаю, почему мне потребовалось так много времени, чтобы понять, но спасибо за ваш вклад в человеческий род.
  • 1
    В быстрых операциях с 4 подстроками возвращается экземпляр типа Substring вместо String. Необходимо преобразовать результат в строку для длительного хранения. let newString = String (substring)
45

ПРИМЕЧАНИЕ. @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"

(Это обязательно должно быть частью языка. Пожалуйста, обманите 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 должно обрабатывать строку для поиска.
  • 11
    @AndrewDunn Это не преждевременная оптимизация. Каждое преобразование из целочисленного индекса в String.Index - это O (n), а не O (1)! Пожалуйста, прочитайте комментарии для advance<T>(…) в пространстве имен Swift .
Показать ещё 5 комментариев
37

На момент написания статьи ни одно расширение не было полностью совместимо с 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) для поддержки, начиная с нуля.

  • 0
    Как это работает с эмодзи и расширенными кластерами графем? (Я должен проверить это сам, но сейчас это не удобно.)
29

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

Подстрочные операции возвращают экземпляр типа подстроки, а не 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
  • 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!

Пожалуйста, посмотрите страницу

  • 0
    работал на меня. Досадно результат показывает как "" в отладчике
  • 0
    Да, у меня были те же проблемы с отладчиком, не показывающим правильную строку несколько раз?
Показать ещё 3 комментария
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, которые будут проверять правильное количество байтов, чтобы перейти к следующей кодовой точке в кодировке. Однако в этом случае проще найти индекс первого пространства в строке, чтобы найти конечный индекс.

15

Так как String является мостом для NSString, "старые" методы должны работать, но неясно, как, например, это тоже не работает (не представляется допустимым синтаксисом):

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

Для меня это действительно интересная часть вашего вопроса. Строка соединяется с NSString, поэтому большинство методов NSString работают непосредственно с String. Вы можете использовать их свободно и без раздумья. Так, например, это работает так, как вы ожидаете:

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

Но, как это часто бывает, "я получил свою работу mojo", но это просто не работает на вас ". Вам просто удалось выбрать один из редких случаев, когда существует параллельный метод с одинаковым именем Swift, и в таком случае метод Swift затмевает метод Objective-C. Таким образом, когда вы говорите str.substringWithRange, Swift думает, что вы имеете в виду метод Swift, а не метод NSString, - и тогда вы будете hosed, потому что метод Swift ожидает Range<String.Index>, и вы не знаете, как сделать один из этих,

Легкий выход - остановить Swift от омрачения таким образом, явно произнося:

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

Обратите внимание, что здесь не задействована значительная дополнительная работа. "Cast" не означает "конвертировать"; Строка фактически является NSString. Мы просто рассказываем Swift, как смотреть эту переменную для этой одной строки кода.

Действительно странная часть всего этого заключается в том, что метод Swift, который вызывает все эти проблемы, недокументирован. Я понятия не имею, где это определено; это не в заголовке NSString, и это также не в заголовке Swift.

  • 0
    Тем не менее, я предлагаю подать ошибку. Apple должна «ловить рыбу или резать наживку» - либо дать нам способ создать Range<String.Index> , либо убрать этот недокументированный метод с нашего пути.
  • 0
    Блин - это полезно. Несмотря на то, что говорится в документации, я не понимал, что происходит, пока не прочитал это. Сейчас отсортировано :)
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:

Изображение 1713

  • 1
    .advancedBy(0) не обязательно для startIndex.
12

Короткий ответ заключается в том, что сейчас это очень сложно в Swift. Моя догадка заключается в том, что для Apple все еще есть куча работы, чтобы делать удобные методы для таких вещей.

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

Как насчет расширения класса String, который принимает старый добрый Int s?

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  name is Patch."
println(dogString[5..<6])               // 
println(dogString[5...5])              // 
println(dogString.substring(5))        //  name is Patch.
println(dogString.substring(5, length: 1))   // 

Обновление: Swift beta 4 разрешает проблемы ниже!

Как и в [бета-версии 3 и более ранних версиях], даже строковые строки Swift имеют некоторые проблемы с обработкой символов Unicode. Значок собаки выше работал, но следующее не делает:

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

Вывод:

1
:
1
️
⃣
  • 1
    Странно, но базовые классы Swift, похоже, лишены множества базовых функций. Я не могу думать, что Apple хочет, чтобы мы постоянно ссылались на классы Foundation для выполнения простых задач.
  • 1
    Полностью. Имейте в виду, что Swift был в основном разработан в темноте, и у каждого свое определение «простых задач» - держу пари, мы видим некоторую быструю итерацию по этим вопросам.
Показать ещё 5 комментариев
11

Вы можете использовать эти расширения для улучшения substringWithRange

Swift 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)
    }
}

Swift 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

Простое решение с небольшим кодом.

Сделайте расширение, которое включает базовое subStringing, которое имеет почти все другие языки:

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' на самом деле означает здесь длину, поэтому я думаю, что его следует переименовать в это.
  • 0
    Я думаю, что использование длины довольно запутанно. На самом деле это конец того места, где вы хотите, чтобы подстрока была, а не фактическая длина результата подстроки.
7

Пример кода для того, как получить подстроку в Swift 2.0

(i) Подстрока от начального индекса

Input: -

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

Надеюсь, это поможет вам!

6

Обновлен для Xcode 7. Добавляет расширение строки:

Использование:

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)
        }
    }

}
6

Это работает на моей площадке:)

String(seq: Array(str)[2...4])
  • 0
    На самом деле это более эффективно, чем звонить advance
  • 2
    Это не работает на моей детской площадке Xcode 7 (Swift 2), но это делает ... 'var str = "Hello, plays" "String (Array (str.characters) [7]) //" p "String (Array ( str.characters) [7 ... 10]) // "play" String (Array (str.characters) [7 .. <10]) // "pla"
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
}
  • 0
    У вас есть ошибка - endIndex должен начинаться с startIndex только на endIndex, а не на расстояние между индексами.
4

попробуйте это на детской площадке

var str:String = "Hello, playground"

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

он даст вам "ello, p"

Однако, когда это становится действительно интересным, так это то, что если вы сделаете последний индекс больше, чем строка на игровой площадке, он покажет строки, которые вы определили после 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))

дает "ello, playground str I'm следующую строку str2"

работает, даже если str2 определяется с let

:)

  • 0
    Я согласен, что это многословно по сравнению с Objective-C, однако все это помещается на одной строке, что является бонусом.
  • 0
    Ну, все еще не хватает одной строки, которая на самом деле печатает подстроку с учетом диапазона, который вы вычислили. Мне нравятся некоторые другие решения, которые создают расширения класса String с использованием вашей логики, но в расширении. Это в конечном итоге решение, которое я выбрал.
Показать ещё 1 комментарий
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

Я пытался придумать что-то Pythonic.

Все индексы здесь велики, но времена, когда мне действительно нужно что-то простое, обычно, когда я хочу рассчитывать со спины, например. 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!!

ИЗМЕНИТЬ

Более элегантное решение:

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!!
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

Взяв страницу с Роба Напира, я разработал эти Common String Extensions, два из которых:

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"
  • 0
    Мне пришлось удалить `- 1`, чтобы получить хорошие результаты.
  • 0
    Вы можете использовать Range вместо Range<String.Index> благодаря выводу типа.
1
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)

Полный образец вы можете увидеть здесь

1

Вот пример, чтобы получить только видео-Id.i.e(6oL687G0Iso) со всего URL в swift

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

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

let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string
let substring = fullString.substringWithRange(range)
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"
0

Swift 3.X +, Xcode 8.X + Протестированное рабочее простое решение;

Использовать просто:

let myString = "12.12.2017 12:34:45"
let newString = myString?[(myString?.startIndex)!..<(myString?.index((myString?.startIndex)!, offsetBy: 10))!]
print(newString) 

Выход = 12.12.2017

Для настройки легко изменить;

offsetBy: 10 // Change 10 to endIndex.

Когда вы меняете offsetBy: от 10 до 15,20 и т.д. Вырезаете строку.

Спасибо!

0

Swift 3.0

Я решил немного поболтать с этим и создать расширение на String. Я, возможно, не использовал слово truncate правильно в том, что у меня есть функция на самом деле.

extension String {

    func truncate(from initialSpot: Int, withLengthOf endSpot: Int) -> String? {

        guard endSpot > initialSpot else { return nil }
        guard endSpot + initialSpot <= self.characters.count else { return nil }

        let truncated = String(self.characters.dropFirst(initialSpot))
        let lastIndex = truncated.index(truncated.startIndex, offsetBy: endSpot)

        return truncated.substring(to: lastIndex)
    }

}

let favGameOfThronesSong = "Light of the Seven"

let word = favGameOfThronesSong.truncate(from: 1, withLengthOf: 4)
// "ight"
  • 0
    Вы публикуете собственное расширение строки? На вопрос, заданный и получивший ответ (с высоко оцененным, принятым ответом) более двух лет назад?
  • 1
    Извини за это. Новая Игра престолов привела меня в восторг. Кроме того, большинство вышеупомянутых решений не работали в новом Xcode с Swift 3.0.
0

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

extension String {

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

Вы можете использовать любой из подстрочных методов в расширении Swift String, я написал https://bit.ly/JString.

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

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

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

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

Приветствия.

  • 0
    Я ненавижу это, но это единственная вещь, которая работает для меня в бета-версии 4.
0

http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-swift/ показывает, что это хорошо работает:

var str = "abcd"
str = str.substringToIndex(1)
  • 2
    Не удалось выполнить игровую площадку: ошибка: <EXPR>: 23: 5: ошибка: тип 'String.Index' не соответствует протоколу 'IntegerLiteralConvertible' str = str.substringToIndex (1) ^
-3

Было много хороших примеров того, как атаковать эту проблему. Первоначальный вопрос заключался в использовании substringWithRange, но, как было указано, это сложнее, чем просто сделать собственное расширение.

Вышеупомянутое решение диапазона хорошо. Вы также можете сделать это еще дюжину способов. Вот еще один пример того, как вы могли это сделать:

extension String{
    func sub(start: Int, length: Int) -> String {
        assert(start >= 0, "Cannot extract from a negative starting index")
        assert(length >= 0, "Cannot extract a negative length string")
        assert(start <= countElements(self) - 1, "cannot start beyond the end")
        assert(start + length <= countElements(self), "substring goes past the end of the original")
        var a = self.substringFromIndex(start)
        var b = a.substringToIndex(length)
        return b
    }
}
var s = "apple12345"
println(s.sub(6, length: 4))
// prints "2345"

Ещё вопросы

Сообщество Overcoder
Наверх
Меню