Получить n-й символ строки в языке программирования Swift

Это действительно тяжелая проблема. Одна из вещей, которую вам нужно сделать, это указать java, что вы используете перечисление. Это означает, что вы расширяете класс Enum для своих дженериков. Однако этот класс не имеет функции values ​​(). Таким образом, вы должны взять класс, для которого вы можете получить значения.

Следующий пример поможет вам исправить вашу проблему:

public <T extends Enum<T>> void enumValues(Class<T> enumType) {
        for (T c : enumType.getEnumConstants()) {
             System.out.println(c.name());
        }
}
376
задан pkamb 10 December 2018 в 21:00
поделиться

40 ответов

Внимание: Пожалуйста, смотрите Ответ Льва Дабуса для правильной реализации Swift 4.

Swift 4

Тип Substring был введен в Swift 4, чтобы сделать подстроки более быстрыми и эффективными за счет совместного использования памяти с исходной строкой, так что именно это должны возвращать функции нижнего индекса.

Попробуйте здесь

extension String {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (bounds: CountableRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ..< end]
  }
  subscript (bounds: CountableClosedRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ... end]
  }
  subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(endIndex, offsetBy: -1)
    return self[start ... end]
  }
  subscript (bounds: PartialRangeThrough<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ... end]
  }
  subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ..< end]
  }
}
extension Substring {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (bounds: CountableRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ..< end]
  }
  subscript (bounds: CountableClosedRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ... end]
  }
  subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(endIndex, offsetBy: -1)
    return self[start ... end]
  }
  subscript (bounds: PartialRangeThrough<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ... end]
  }
  subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ..< end]
  }
}

Чтобы преобразовать Substring в String, вы можете просто сделать String(string[0..2]), но вы должны делать это только если вы планирую держать подстроку вокруг. В противном случае более эффективно сохранить его Substring.

1137 Было бы замечательно, если бы кто-нибудь смог найти хороший способ объединить эти два расширения в одно. Я попытался расширить StringProtocol безуспешно, потому что метод index там не существует.

& nbsp;

Swift 3:

extension String {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (i: Int) -> String {
    return String(self[i] as Character)
  }
  subscript (r: Range<Int>) -> String {
    let start = index(startIndex, offsetBy: r.lowerBound)
    let end = index(startIndex, offsetBy: r.upperBound)
    return self[Range(start ..< end)]
  }
}

& nbsp;

Почему это не встроено?

Apple предоставляет следующее объяснение ( найдено здесь ):

Подписывание строк с целыми числами недоступно.

Понятие «i-й символ в строке» имеет разные интерпретации в разных библиотеках и компонентах системы. Правильная интерпретация должна быть выбрана в соответствии со случаем использования и задействованными API, поэтому String не может быть подписано целым числом.

Swift предоставляет несколько различных способов доступа к символьным данным, хранящимся внутри строк.

  • String.utf8 - это набор кодовых единиц UTF-8 в строке. Используйте этот API при преобразовании строки в UTF-8. Большинство API POSIX обрабатывают строки в единицах кода UTF-8.

  • String.utf16 - это набор кодовых единиц UTF-16 в виде строки. Большинство сенсорных API-интерфейсов Какао и Какао обрабатывают строки в единицах кода UTF-16. Например, экземпляры NSRange, используемые с NSAttributedString и NSRegularExpression, хранят смещения и длины подстрок в единицах кода UTF-16.

  • String.unicodeScalars - это коллекция скаляров Unicode. Используйте этот API, когда вы выполняете низкоуровневую манипуляцию с символьными данными.

  • String.characters представляет собой набор расширенных кластеров графем, которые являются приближением воспринимаемых пользователем символов.

Обратите внимание, что при обработке строк, содержащих читаемый человеком текст, следует избегать посимвольной обработки в максимально возможной степени. Вместо этого используйте высокоуровневые чувствительные к локали алгоритмы Unicode, например, String.localizedStandardCompare(), String.localizedLowercaseString, String.localizedStandardRangeOfString() и т. Д.

537
ответ дан aleclarson 10 December 2018 в 21:00
поделиться

Swift 4.2

Этот ответ является идеальным, поскольку он расширяет String и все его Subsequences (Substring) в одном расширении

public extension StringProtocol {

    public subscript (i: Int) -> Element {
        return self[index(startIndex, offsetBy: i)]
    }

    public subscript (bounds: CountableClosedRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start...end]
    }

    public subscript (bounds: CountableRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start..<end]
    }

    public subscript (bounds: PartialRangeUpTo<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex..<end]
    }

    public subscript (bounds: PartialRangeThrough<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex...end]
    }

    public subscript (bounds: CountablePartialRangeFrom<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        return self[start..<endIndex]
    }
}

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

var str = "Hello, playground"

print(str[5...][...5][0])
// Prints ","
2
ответ дан Noah Wilder 10 December 2018 в 21:00
поделиться

Python-подобное решение, которое позволяет использовать отрицательный индекс,

var str = "Hello world!"
str[-1]        // "!"

может быть:

extension String {
    subscript (var index:Int)->Character{
        get {
            let n = distance(self.startIndex, self.endIndex)
            index %= n
            if index < 0 { index += n }
            return self[advance(startIndex, index)]
        }
    }
}

Кстати, может быть, стоит перенести целая нотация среза питона

1
ответ дан Community 10 December 2018 в 21:00
поделиться

В Swift 3 без расширений для класса String, настолько просто, насколько я могу это сделать!

let myString = "abcedfg"
let characterLocationIndex = myString.index(myString.startIndex, offsetBy: 3)
let myCharacter = myString[characterLocationIndex]

myCharacter равно «3» в этом примере.

1
ответ дан John Pavley 10 December 2018 в 21:00
поделиться

Использование символов сделает работу. Вы можете быстро преобразовать строку в массив символов, которыми можно манипулировать с помощью методов CharacterView.

Пример:

let myString = "Hello World!"
let myChars  = myString.characters

(полный CharacterView документ)

(протестировано в Swift 3)

1
ответ дан Stephane Paquet 10 December 2018 в 21:00
поделиться

Есть альтернатива, объясненная в Струнном манифесте

extension String : BidirectionalCollection {
    subscript(i: Index) -> Character { return characters[i] }
}
1
ответ дан George Maisuradze 10 December 2018 в 21:00
поделиться

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

// Pay up front for O(N) memory
let chars = Array(veryLargeString.characters)

for i in 0...veryLargeNumber {
    // Benefit from O(1) access
    print(chars[i])
}
0
ответ дан Joseph Chen 10 December 2018 в 21:00
поделиться

Позволяет использовать отрицательные индексы

Всегда полезно не всегда писать string[string.length - 1], чтобы получить последний символ при использовании расширения нижнего индекса. Это расширение ( Swift 3 ) допускает отрицательные индексы Range и CountableClosedRange.

extension String {
    var count: Int { return self.characters.count }

    subscript (i: Int) -> Character {
        // wraps out of bounds indices
        let j = i % self.count
        // wraps negative indices
        let x = j < 0 ? j + self.count : j

        // quick exit for first
        guard x != 0 else {
            return self.characters.first!
        }

        // quick exit for last
        guard x != count - 1 else {
            return self.characters.last!
        }

        return self[self.index(self.startIndex, offsetBy: x)]
    }

    subscript (r: Range<Int>) -> String {
        let lb = r.lowerBound
        let ub = r.upperBound

        // quick exit for one character
        guard lb != ub else { return String(self[lb]) }

        return self[self.index(self.startIndex, offsetBy: lb)..<self.index(self.startIndex, offsetBy: ub)]
    }

    subscript (r: CountableClosedRange<Int>) -> String {
        return self[r.lowerBound..<r.upperBound + 1]
    }
}

Как его использовать:

var text = "Hello World"

text[-1]    // d
text[2]     // l
text[12]    // e
text[0...4] // Hello
text[0..<4] // Hell

Для более тщательного программиста: включите guard против пустых строк в этом расширении

subscript (i: Int) -> Character {
    guard self.count != 0 else { return '' }
    ...
}

subscript (r: Range<Int>) -> String {
    guard self.count != 0 else { return "" }
    ...
}
0
ответ дан Jay Harris 10 December 2018 в 21:00
поделиться

Swift 3:

extension String {
    func substring(fromPosition: UInt, toPosition: UInt) -> String? {
        guard fromPosition <= toPosition else {
            return nil
        }

        guard toPosition < UInt(characters.count) else {
            return nil
        }

        let start = index(startIndex, offsetBy: String.IndexDistance(fromPosition))
        let end   = index(startIndex, offsetBy: String.IndexDistance(toPosition) + 1)
        let range = start..<end

        return substring(with: range)
    }
}

"ffaabbcc".substring(fromPosition: 2, toPosition: 5) // return "aabb"
0
ответ дан Daniele Ceglia 10 December 2018 в 21:00
поделиться

Проверьте, что это Swift 4

let myString = "LOVE"

self.textField1.text = String(Array(myString)[0])
self.textField2.text = String(Array(myString)[1])
self.textField3.text = String(Array(myString)[2])
self.textField4.text = String(Array(myString)[3])
0
ответ дан Sreekanth G 10 December 2018 в 21:00
поделиться

один из лучших и самых простых способов

        let yourString = "thisString"
        print(Array(yourString)[8])

помещает каждую букву вашей строки в массивы, а затем вы выбираете девятую

-2
ответ дан bibble triple 10 December 2018 в 21:00
поделиться

Получите первую букву:

first(str) // retrieve first letter

Подробнее здесь: http://sketchytech.blogspot.com/2014/08/swift-pure-swift-method -для-returning.html

1
ответ дан Noah Wilder 10 December 2018 в 21:00
поделиться

Обновление для подстроки swift 2.0

public extension String {
    public subscript (i: Int) -> String {
        return self.substringWithRange(self.startIndex..<self.startIndex.advancedBy(i + 1))
    }

    public subscript (r: Range<Int>) -> String {
        get {
            return self.substringWithRange(self.startIndex.advancedBy(r.startIndex)..<self.startIndex.advancedBy(r.endIndex))
        }
    }

}
2
ответ дан YannSteph 10 December 2018 в 21:00
поделиться

Swift 3

extension String {

    public func charAt(_ i: Int) -> Character {
        return self[self.characters.index(self.startIndex, offsetBy: i)]
    }

    public subscript (i: Int) -> String {
        return String(self.charAt(i) as Character)
    }

    public subscript (r: Range<Int>) -> String {
        return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
    }

    public subscript (r: CountableClosedRange<Int>) -> String {
        return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
    }

}

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

let str = "Hello World"
let sub = str[0...4]

Полезные советы по программированию и трюки (написано меня)

2
ответ дан quemeful 10 December 2018 в 21:00
поделиться

Нет индексации с использованием целых чисел, только с использованием String.Index. В основном с линейной сложностью. Вы также можете создавать диапазоны из String.Index и получать подстроки, используя их.

Swift 3.0

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.index(before: someString.endIndex)]
let charAtIndex = someString[someString.index(someString.startIndex, offsetBy: 10)]

let range = someString.startIndex..<someString.index(someString.startIndex, offsetBy: 10)
let substring = someString[range]

Swift 2.x

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.endIndex.predecessor()]
let charAtIndex = someString[someString.startIndex.advanceBy(10)]

let range = someString.startIndex..<someString.startIndex.advanceBy(10)
let subtring = someString[range]

Обратите внимание, что вы никогда не сможете использовать индекс ( или диапазон), созданный из одной строки в другую

let index10 = someString.startIndex.advanceBy(10)

//will compile
//sometimes it will work but sometimes it will crash or result in undefined behaviour
let charFromAnotherString = anotherString[index10]
122
ответ дан CodeBender 10 December 2018 в 21:00
поделиться

Я думаю, что быстрый ответ для получения первого символа может быть:

let firstCharacter = aString[aString.startIndex]

Это намного элегантнее и эффективнее, чем:

let firstCharacter = Array(aString.characters).first

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

extension String {
var length : Int {
    return self.characters.count
}

subscript(integerIndex: Int) -> Character {
    let index = startIndex.advancedBy(integerIndex)
    return self[index]
}

subscript(integerRange: Range<Int>) -> String {
    let start = startIndex.advancedBy(integerRange.startIndex)
    let end = startIndex.advancedBy(integerRange.endIndex)
    let range = start..<end
    return self[range]
}

}

НО ЭТО УЖАСНАЯ ИДЕЯ !!

Расширение ниже ужасно неэффективно. Каждый раз, когда к строке обращаются с помощью целого числа, запускается функция O (n) для продвижения ее начального индекса. Запуск линейного цикла внутри другого линейного цикла означает, что этот цикл for случайно равен O (n2) - при увеличении длины строки время, которое занимает этот цикл, увеличивается квадратично.

Вместо этого вы можете использовать коллекцию строк символов.

2
ответ дан ignaciohugog 10 December 2018 в 21:00
поделиться

Класс быстрой строки не предоставляет возможности получить символ по определенному индексу из-за его собственной поддержки символов UTF. Переменная длина символа UTF в памяти делает невозможным переход непосредственно к символу. Это означает, что вы должны вручную зацикливать строку каждый раз.

Вы можете расширить String для предоставления метода, который будет циклически проходить по символам до нужного вам индекса

extension String {
    func characterAtIndex(index: Int) -> Character? {
        var cur = 0
        for char in self {
            if cur == index {
                return char
            }
            cur++
        }
        return nil
    }
}

myString.characterAtIndex(0)!
11
ответ дан drewag 10 December 2018 в 21:00
поделиться

Swift3

Вы можете использовать синтаксис индекса для доступа к Персонажу по определенному строковому индексу.

let greeting = "Guten Tag!"
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index] // a

Посетите https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html

или мы можем сделать строку Расширение в Swift 4

extension String {
    func getCharAtIndex(_ index: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: index)]
    }
}

ИСПОЛЬЗОВАНИЕ:

let foo = "ABC123"
foo.getCharAtIndex(2) //C
3
ответ дан Basil Mariano 10 December 2018 в 21:00
поделиться

Swift 4.2 и более ранние

let str = "abcdef"
str[1 ..< 3] // returns "bc"
str[5] // returns "f"
str[80] // returns ""
str.substring(fromIndex: 3) // returns "def"
str.substring(toIndex: str.length - 2) // returns "abcd"

Вам необходимо добавить это расширение String в свой проект (оно полностью протестировано):

extension String {

  var length: Int {
    return count
  }

  subscript (i: Int) -> String {
    return self[i ..< i + 1]
  }

  func substring(fromIndex: Int) -> String {
    return self[min(fromIndex, length) ..< length]
  }

  func substring(toIndex: Int) -> String {
    return self[0 ..< max(0, toIndex)]
  }

  subscript (r: Range<Int>) -> String {
    let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                        upper: min(length, max(0, r.upperBound))))
    let start = index(startIndex, offsetBy: range.lowerBound)
    let end = index(start, offsetBy: range.upperBound - range.lowerBound)
    return String(self[start ..< end])
  }

}

Даже при том, что У Swift всегда было готовое решение этой проблемы (без расширения String, которое я предоставил ниже), я все же настоятельно рекомендовал бы использовать расширение. Зачем? Потому что это избавило меня от десятков часов мучительной миграции с ранних версий Swift, где синтаксис String менялся почти в каждом выпуске, но все, что мне нужно было сделать, это обновить реализацию расширения, а не рефакторинг всей 300-килограммовой строки кода. приложение. Сделай свой выбор.

let str = "Hello, world!"
let index = str.index(str.startIndex, offsetBy: 4)
str[index] // returns Character 'o'

let endIndex = str.index(str.endIndex, offsetBy:-2)
str[index ..< endIndex] // returns String "o, worl"

String(str.suffix(from: index)) // returns String "o, world!"
String(str.prefix(upTo: index)) // returns String "Hell"
309
ответ дан NAlexN 10 December 2018 в 21:00
поделиться

Если вы видите Cannot subscript a value of type 'String'..., используйте это расширение:

Swift 3

extension String {
    subscript (i: Int) -> Character {
        return self[self.characters.index(self.startIndex, offsetBy: i)]
    }

    subscript (i: Int) -> String {
        return String(self[i] as Character)
    }

    subscript (r: Range<Int>) -> String {
        let start = index(startIndex, offsetBy: r.lowerBound)
        let end = index(startIndex, offsetBy: r.upperBound)
        return self[start..<end]
    }

    subscript (r: ClosedRange<Int>) -> String {
        let start = index(startIndex, offsetBy: r.lowerBound)
        let end = index(startIndex, offsetBy: r.upperBound)
        return self[start...end]
    }
}

Swift 2.3

extension String {
    subscript(integerIndex: Int) -> Character {
        let index = advance(startIndex, integerIndex)
        return self[index]
    }

    subscript(integerRange: Range<Int>) -> String {
        let start = advance(startIndex, integerRange.startIndex)
        let end = advance(startIndex, integerRange.endIndex)
        let range = start..<end
        return self[range]
    }
}

Источник: http://oleb.net/blog/2014/07/swift-strings/

23
ответ дан SoftDesigner 10 December 2018 в 21:00
поделиться

Для того, чтобы скормить тему и показать возможности быстрого подстрочного индекса, вот небольшая строковая подстрока «substring-toolbox» на основе

Эти методы безопасны и никогда не идут через строковые индексы

extension String {
    // string[i] -> one string char
    subscript(pos: Int) -> String { return String(Array(self)[min(self.length-1,max(0,pos))]) }

    // string[pos,len] -> substring from pos for len chars on the left
    subscript(pos: Int, len: Int) -> String { return self[pos, len, .pos_len, .left2right] }

    // string[pos, len, .right2left] -> substring from pos for len chars on the right
    subscript(pos: Int, len: Int, way: Way) -> String { return self[pos, len, .pos_len, way] }

    // string[range] -> substring form start pos on the left to end pos on the right
    subscript(range: Range<Int>) -> String { return self[range.startIndex, range.endIndex, .start_end, .left2right] }

    // string[range, .right2left] -> substring start pos on the right to end pos on the left
    subscript(range: Range<Int>, way: Way) -> String { return self[range.startIndex, range.endIndex, .start_end, way] }

    var length: Int { return countElements(self) }
    enum Mode { case pos_len, start_end }
    enum Way { case left2right, right2left }
    subscript(var val1: Int, var val2: Int, mode: Mode, way: Way) -> String {
        if mode == .start_end {
            if val1 > val2 { let val=val1 ; val1=val2 ; val2=val }
            val2 = val2-val1
        }
        if way == .left2right {
            val1 = min(self.length-1, max(0,val1))
            val2 = min(self.length-val1, max(1,val2))
        } else {
            let val1_ = val1
            val1 = min(self.length-1, max(0, self.length-val1_-val2 ))
            val2 = max(1, (self.length-1-val1_)-(val1-1) )
        }
        return self.bridgeToObjectiveC().substringWithRange(NSMakeRange(val1, val2))

        //-- Alternative code without bridge --
        //var range: Range<Int> = pos...(pos+len-1)
        //var start = advance(startIndex, range.startIndex)
        //var end = advance(startIndex, range.endIndex)
        //return self.substringWithRange(Range(start: start, end: end))
    }
}


println("0123456789"[3]) // return "3"

println("0123456789"[3,2]) // return "34"

println("0123456789"[3,2,.right2left]) // return "56"

println("0123456789"[5,10,.pos_len,.left2right]) // return "56789"

println("0123456789"[8,120,.pos_len,.right2left]) // return "01"

println("0123456789"[120,120,.pos_len,.left2right]) // return "9"

println("0123456789"[0...4]) // return "01234"

println("0123456789"[0..4]) // return "0123"

println("0123456789"[0...4,.right2left]) // return "56789"

println("0123456789"[4...0,.right2left]) // return "678" << because ??? range can wear endIndex at 0 ???
2
ответ дан Luc-Olivier 10 December 2018 в 21:00
поделиться

Мое очень простое решение:

let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]
4
ответ дан Linh Dao 10 December 2018 в 21:00
поделиться

Тип Swift String не предоставляет метод characterAtIndex, поскольку существует несколько способов кодирования строки Unicode. Собираетесь ли вы с UTF8, UTF16 или чем-то еще?

Вы можете получить доступ к коллекциям CodeUnit, найдя свойства String.utf8 и String.utf16. Вы также можете получить доступ к коллекции UnicodeScalar, найдя свойство String.unicodeScalars.

В духе реализации NSString я возвращаю тип unichar.

extension String
{
    func characterAtIndex(index:Int) -> unichar
    {
        return self.utf16[index]
    }

    // Allows us to use String[index] notation
    subscript(index:Int) -> unichar
    {
        return characterAtIndex(index)
    }
}

let text = "Hello Swift!"
let firstChar = text[0]
1
ответ дан Erik 10 December 2018 в 21:00
поделиться

Вы можете использовать SwiftString ( https://github.com/amayne/SwiftString ), чтобы сделать это.

"Hello, world!"[0] // H
"Hello, world!"[0...4] // Hello

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я написал это расширение

0
ответ дан eurobrew 10 December 2018 в 21:00
поделиться

Вот расширение, которое вы можете использовать, работая с Swift 3.1. Один индекс вернет Character, что кажется интуитивно понятным при индексации String, а Range вернет String.

extension String {
    subscript (i: Int) -> Character {
        return Array(self.characters)[i]
    }

    subscript (r: CountableClosedRange<Int>) -> String {
        return String(Array(self.characters)[r])
    }

    subscript (r: CountableRange<Int>) -> String {
        return self[r.lowerBound...r.upperBound-1]
    }
}

Некоторые примеры расширения в действии:

let string = "Hello"

let c1 = string[1]  // Character "e"
let c2 = string[-1] // fatal error: Index out of range

let r1 = string[1..<4] // String "ell"
let r2 = string[1...4] // String "ello"
let r3 = string[1...5] // fatal error: Array index is out of range



n.b. Вы можете добавить дополнительный метод к вышеприведенному расширению, чтобы при желании возвращать String с одним символом:

subscript (i: Int) -> String {
    return String(self[i])
}

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

let c: Character = string[3] // Character "l"
let s: String = string[0]    // String "H"
1
ответ дан Matt Le Fleur 10 December 2018 в 21:00
поделиться

Swift 4

Подписка по диапазону и частичному диапазону с использованием свойства String indices

Как вариант @LeoDabus хороший ответ , мы можем добавить дополнительное расширение к DefaultBidirectionalIndices с целью позволить нам использовать свойство indices String при реализации пользовательских подписок (с помощью Int специализированных диапазонов и частичные диапазоны) для последнего.

extension DefaultBidirectionalIndices {
    subscript(at: Int) -> Elements.Index {
        return index(startIndex, offsetBy: at)
    }
}

// Moving the index(_:offsetBy:) to an extension yields slightly
// briefer implementations for these String extensions.
extension String {
    subscript(r: CountableClosedRange<Int>) -> SubSequence {
        return self[indices[r.lowerBound]...indices[r.upperBound]]
    }
    subscript(r: CountablePartialRangeFrom<Int>) -> SubSequence {
        return self[indices[r.lowerBound]...]
    }
    subscript(r: PartialRangeThrough<Int>) -> SubSequence {
        return self[...indices[r.upperBound]]
    }
    subscript(r: PartialRangeUpTo<Int>) -> SubSequence {
        return self[..<indices[r.upperBound]]
    }
}

let str = "foo bar baz bax"
print(str[4...6]) // "bar"
print(str[4...])  // "bar baz bax"
print(str[...6])  // "foo bar"
print(str[..<6])  // "foo ba"

Спасибо @LeoDabus за то, что он указал мне на направление использования свойства indices в качестве (другой) альтернативы подписке String!

Swift 4.2.

В Swift 4.2, DefaultBidirectionalIndices устарела в пользу DefaultIndices .

2
ответ дан Leo Dabus 10 December 2018 в 21:00
поделиться

Xcode 10.2 • Swift 5

Вы можете расширить StringProtocol, чтобы сделать индекс доступным также для подстрок:

extension StringProtocol {        
    subscript(offset: Int) -> Element {
        return self[index(startIndex, offsetBy: offset)]
    }
    subscript(_ range: Range<Int>) -> SubSequence {
        return prefix(range.lowerBound + range.count)
            .suffix(range.count)
    }
    subscript(range: ClosedRange<Int>) -> SubSequence {
        return prefix(range.lowerBound + range.count)
            .suffix(range.count)
    }
    subscript(range: PartialRangeThrough<Int>) -> SubSequence {
        return prefix(range.upperBound.advanced(by: 1))
    }
    subscript(range: PartialRangeUpTo<Int>) -> SubSequence {
        return prefix(range.upperBound)
    }
    subscript(range: PartialRangeFrom<Int>) -> SubSequence {
        return suffix(Swift.max(0, count - range.lowerBound))
    }
}

extension LosslessStringConvertible {
    var string: String { return .init(self) }
}

extension BidirectionalCollection {
    subscript(safe offset: Int) -> Element? {
        guard !isEmpty, let i = index(startIndex, offsetBy: offset, limitedBy: index(before: endIndex)) else { return nil }
        return self[i]
    }
}
<час>

Тестирование

let test = "Hello USA                   
101
ответ дан Leo Dabus 10 December 2018 в 21:00
поделиться

Swift 4

String(Array(stringToIndex)[index]) 

Это, вероятно, лучший способ решения этой проблемы за один раз. Вы, вероятно, хотите сначала привести String как массив, а затем снова привести результат как String. В противном случае, символ будет возвращен вместо строки.

Пример String(Array("HelloThere")[1]) вернет «е» в виде строки.

(Array("HelloThere")[1] вернет «е» как символ.

Swift не позволяет индексировать строки как массивы, но это делает работу в стиле грубой силы.

11
ответ дан Harsh G. 10 December 2018 в 21:00
поделиться

Мое решение в одной строке, предположим, что кадена - это строка, а 4 - это n-я позиция, которую вы хотите:

let character = cadena[advance(cadena.startIndex, 4)]

Простая ... Я предполагаю, что Swift включит больше вещей о подстроках в будущих версиях .

3
ответ дан Julio César Fernández Muñoz 10 December 2018 в 21:00
поделиться

Swift 2.0 от Xcode 7 GM Seed

var text = "Hello, world!"

let firstChar = text[text.startIndex.advancedBy(0)] // "H"

Для n-го символа замените 0 на n-1.

Редактировать: Swift 3.0

text[text.index(text.startIndex, offsetBy: 0)]


н.б. Существуют более простые способы ввода определенных символов в строку

, например. let firstChar = text.characters.first

24
ответ дан Matt Le Fleur 10 December 2018 в 21:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: