By Mohsen


2014-06-07 01:50:31 8 Comments

How can I get the nth character of a string? I tried bracket([]) accessor with no luck.

var string = "Hello, world!"

var firstChar = string[0] // Throws error

ERROR: 'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion

30 comments

@Emre DeฤŸirmenci 2020-01-24 21:43:20

In Swift 5 without extension to the String :

var str = "ABCDEFGH"
for char in str {
if(char == "C") { }
}

Above Swift code as same as that Java code :

int n = 8;
var str = "ABCDEFGH"
for (int i=0; i<n; i++) {
if (str.charAt(i) == 'C') { }
}

@Yodagama 2019-12-28 16:48:11

By now, subscript(_:) is unavailable. As well as we can't do this

str[0] 

with string.We have to provide "String.Index" But, how can we give our own index number in this way, instead we can use,

string[str.index(str.startIndex, offsetBy: 0)]

@Pedram Parsian 2019-12-28 19:03:58

Please edit your answer and add some context by explaining how your answer solves the problem, instead of posting code-only answer. From Review

@Cristik 2019-12-28 19:40:15

Why doing the unnecessary offset-ing? Why not simply string[string.startIndex]? BTW, the code would not correctly behave/compile, as you used two different variable names.

@aleclarson 2014-06-10 15:02:33

Attention: Please see Leo Dabus' answer for a proper implementation for Swift 4 and Swift 5.

Swift 4

The Substring type was introduced in Swift 4 to make substrings faster and more efficient by sharing storage with the original string, so that's what the subscript functions should return.

Try it out here

extension StringProtocol {
    subscript(offset: Int) -> Character { self[index(startIndex, offsetBy: offset)] }
    subscript(range: CountableRange<Int>) -> SubSequence {
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        return self[startIndex..<index(startIndex, offsetBy: range.count)]
    }
    subscript(range: ClosedRange<Int>) -> SubSequence {
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        return self[startIndex..<index(startIndex, offsetBy: range.count)]
    }
    subscript(range: CountablePartialRangeFrom<Int>) -> SubSequence { self[index(startIndex, offsetBy: range.lowerBound)...] }
    subscript(range: PartialRangeThrough<Int>) -> SubSequence { self[...index(startIndex, offsetBy: range.upperBound)] }
    subscript(range: PartialRangeUpTo<Int>) -> SubSequence { self[..<index(startIndex, offsetBy: range.upperBound)] }
}

To convert the Substring into a String, you can simply do String(string[0..2]), but you should only do that if you plan to keep the substring around. Otherwise, it's more efficient to keep it a Substring.

It would be great if someone could figure out a good way to merge these two extensions into one. I tried extending StringProtocol without success, because the index method does not exist there.


Why is this not built-in?

Apple provides the following explanation (found here):

Subscripting strings with integers is not available.

The concept of "the ith character in a string" has different interpretations in different libraries and system components. The correct interpretation should be selected according to the use case and the APIs involved, so String cannot be subscripted with an integer.

Swift provides several different ways to access the character data stored inside strings.

  • String.utf8 is a collection of UTF-8 code units in the string. Use this API when converting the string to UTF-8. Most POSIX APIs process strings in terms of UTF-8 code units.

  • String.utf16 is a collection of UTF-16 code units in string. Most Cocoa and Cocoa touch APIs process strings in terms of UTF-16 code units. For example, instances of NSRange used with NSAttributedString and NSRegularExpression store substring offsets and lengths in terms of UTF-16 code units.

  • String.unicodeScalars is a collection of Unicode scalars. Use this API when you are performing low-level manipulation of character data.

  • String.characters is a collection of extended grapheme clusters, which are an approximation of user-perceived characters.

Note that when processing strings that contain human-readable text, character-by-character processing should be avoided to the largest extent possible. Use high-level locale-sensitive Unicode algorithms instead, for example, String.localizedStandardCompare(), String.localizedLowercaseString, String.localizedStandardRangeOfString() etc.

@John LaBarge 2015-05-26 19:12:26

Right but it doesn't do the range adaptation for slicing a string that the above solution solves so elegantly.

@user246672 2015-06-19 02:33:19

Cannot find an overload for 'advance' that accepts an argument list of type '(String.Index, T)' ... String.Index and Int aren't compatible.

@aleclarson 2015-06-19 07:10:22

@Barry That's more than likely because of the Swift 2.0 release. I'm not using Swift right now, so if someone could update this answer, I'm sure people would appreciate it.

@SoftDesigner 2015-07-07 09:57:35

If you see Cannot subscript a value of type 'String'... check this answer: stackoverflow.com/a/31265316/649379

@Aaron 2015-09-24 20:28:48

I am getting fatal error: can not increment endIndex

@Sulthan 2015-10-11 15:41:06

the last operation could seriously improve performance by first getting the start index as let start = startIndex.advancedBy(r.startIndex) and using it as the starting point for end index let end = start.advanceBy(r.endIndex - r.startIndex).

@duthen 2016-01-08 16:12:11

It seems you can replace return substringWithRange(Range(start: startIndex.advancedBy(r.startIndex), end: startIndex.advancedBy(r.endIndex))) by return self[Range(start: startIndex.advancedBy(r.startIndex), end: startIndex.advancedBy(r.endIndex))]

@jowie 2016-03-02 16:55:47

When I try to use this, I get Ambiguous use of 'subscript'.

@Craig.Pearce 2016-05-03 04:13:48

@aleclarson Looks like this will have some issues with Swift 3. init(start:end:) is deprecated.

@nekonari 2016-05-18 17:18:59

Why are you using "==="? That's identity operator for objects not comparing values..

@ignaciohugog 2016-06-18 17:21:34

WARNING! The extension below is horribly inefficient. Every time a string is accessed with an integer, an O(n) function to advance its starting index is run. Running a linear loop inside another linear loop means this for loop is accidentally O(n2) โ€” as the length of the string increases, the time this loop takes increases quadratically. Instead of doing that you could use the characters's string collection.

@Randel G. Smith 2016-06-20 18:43:12

@ignaciohugog Do you think String.CharacterView.Index.successor() is O(1) or O(N)? I couldn't find any O() info for .successor() or .predecessor(). Thanks.

@Devin B 2016-06-22 21:29:16

fatal error: Can't form a Character from an empty String

@Jack 2016-08-12 02:07:41

Can I add this to a utilities file I am making that I eventually wish to pass to GitHub?

@Thomas 2016-09-14 21:18:18

I'm getting a couple errors when trying to use this with xCode 8

@BennX 2017-03-19 17:24:59

For those who get Ambiguous use of 'subscript' typehint to the variable type since "someString"[5] can either return a String or a Character with the shown subscripts. You need to tell him what you need. @jowie

@Honey 2018-04-26 13:31:16

I'm confused. So is there any case where the Swift3 answer won't work? If not what Apple did makes no sense

@Noah Wilder 2018-04-27 22:31:27

Check out my answer, it uses the same thing (credit to @alecarlson), but you can get and set the subscript.

@Leo Dabus 2018-08-31 11:25:18

This method as it is unnecessarily offsetting both bounds from the startIndex. What you should do to avoid that is offset the endIndex starting from the start (not the startIndex) offsetBy the range count. Regarding the StringProtocol subscript extension I have already posted it.

@aleclarson 2018-08-31 13:01:43

@LeoDabus I edited my answer to recommend yours. Good work!

@Leo Dabus 2018-08-31 13:04:45

@aleclarson Just change startIndex to start and upperBound to count when defining the end index. This is probably the reason of 20 downvotes. Also cast Character to Character in your Swift 3 version is pointless

@aleclarson 2018-08-31 13:05:58

@LeoDabus Feel free to make those edits yourself instead of telling me to do so. :)

@Michael Austin 2019-02-03 00:56:54

@ignaciohugog wait. I think it ends up being more like O(n!)

@Josh R 2019-12-07 00:27:37

Swift 5.1

Here might be the easiest solution out of all these answers.

Add this extension:

extension String {
    func retrieveFirstCharacter() -> String? {
        guard self.count > 0 else { return nil }
        let numberOfCharacters = self.count
        return String(self.dropLast(numberOfCharacters - 1))
    }
}

@Cristik 2019-12-28 19:41:01

Shouldn't a method named retrieveFirstCharacter return a Character?

@Leo Dabus 2016-07-06 02:40:52

Xcode 11 โ€ข Swift 5.1

You can extend StringProtocol to make the subscript available also to the substrings:

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

extension LosslessStringConvertible {
    var string: String { .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]
    }
}

Testing

let test = "Hello USA ๐Ÿ‡บ๐Ÿ‡ธ!!! Hello Brazil ๐Ÿ‡ง๐Ÿ‡ท!!!"
test[safe: 10]   // "๐Ÿ‡บ๐Ÿ‡ธ"
test[11]   // "!"
test[10...]   // "๐Ÿ‡บ๐Ÿ‡ธ!!! Hello Brazil ๐Ÿ‡ง๐Ÿ‡ท!!!"
test[10..<12]   // "๐Ÿ‡บ๐Ÿ‡ธ!"
test[10...12]   // "๐Ÿ‡บ๐Ÿ‡ธ!!"
test[...10]   // "Hello USA ๐Ÿ‡บ๐Ÿ‡ธ"
test[..<10]   // "Hello USA "
test.first   // "H"
test.last    // "!"

// Subscripting the Substring
 test[...][...3]  // "Hell"

// Note that they all return a Substring of the original String.
// To create a new String from a substring
test[10...].string  // "๐Ÿ‡บ๐Ÿ‡ธ!!! Hello Brazil ๐Ÿ‡ง๐Ÿ‡ท!!!"

@allenlinli 2016-09-22 13:12:05

May I ask what is "self[index(startIndex, offsetBy: i)]"? And how does "self[i]" work?

@Ahmet Akkök 2016-10-03 14:56:11

Hi Leo, thank you for the solution! I just (today) switched to from Swift 2.3 to 3 and your solution subscript(range: Range<Int>) gives the error "Extra argument 'limitedBy' in call". What do you think can be wrong?

@Leo Dabus 2016-10-03 15:26:10

@AhmetAkkök are you sure you didn't change the code?

@Ahmet Akkök 2016-10-03 15:57:14

@Leo it turned out I did not convert the whole project but on the app not the extension, I'have repeated the process for both app and the extension and it works OK now. Your help is very much appreciated!

@Dan Rosenstark 2016-11-07 16:25:29

this is very complicated code. What's the advantage over doing return String(Array(characters)[range]) in Swift 3?

@Noah Wilder 2018-04-25 22:14:16

Why did you choose to return SubSequence rather than a value like SubString or String?

@Leo Dabus 2018-04-25 22:18:21

I am extending the protocol not the type (String) so you need to return SubSequence which in the case of a String is a Substring.

@Nostradamus 2019-05-11 12:48:01

Tells you all you need to know about how messed up Swift is currently.

@Emre DeฤŸirmenci 2020-01-24 14:30:53

I want to use Java charAt(i) usage in my Swift string traverse within for loop without writing extension or another loop. How can I do ?

@Soeng Saravit 2019-10-11 09:48:18

You can do it by convert String into Array and get it by specific index using subscript as below

var str = "Hello"
let s = Array(str)[2]
print(s)

@Cristik 2019-12-28 19:42:16

Note that this solution will result in contents duplication, making it less performant memory wise and CPU-wise.

@Linh Dao 2018-03-02 04:13:15

My very simple solution:

Swift 4.1:

let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]

Swift 5.1:

let firstCharacter = myString[String.Index.init(utf16Offset: index, in: myString)]

@leanne 2018-08-25 18:09:09

Works in Swift 4.1

@OhadM 2019-09-21 12:19:31

Simplest solution and now with Swift 5 example :)

@nalexn 2014-11-06 09:32:48

Swift 5 and earlier

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"

You will need to add this String extension to your project (it's fully tested):

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

}

Even though Swift always had out of the box solution to this problem (without String extension, which I provided below), I still would strongly recommend using the extension. Why? Because it saved me tens of hours of painful migration from early versions of Swift, where String's syntax was changing almost every release, but all I needed to do was to update the extension's implementation as opposed to refactoring the entire project. Make your choice.

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"

@Leo Dabus 2017-10-25 23:32:38

change range.upperBound - range.lowerBound to range.count

@Chris Prince 2017-11-06 23:57:35

It's not part of the original question, but... it would be nice if this supported assignment too. E.g., s[i] = "a" :).

@C0D3 2018-10-14 15:14:27

I believe with Swift 4.2 subscripts are not available again. I get an error saying: 'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion

@Leo Dabus 2018-12-11 03:08:14

@ChrisPrince extension StringProtocol where Self: RangeReplaceableCollection { subscript(offset: Int) -> Element { get { return self[index(startIndex, offsetBy: offset)] } set { let start = index(startIndex, offsetBy: offset) replaceSubrange(start..<index(after: start), with: [newValue]) } } }

@bibble triple 2019-03-30 20:44:15

prob one of the best and simpliest way

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

puts each letters of your string into arrrays and then you sellect the 9th one

@ayaio 2019-03-30 21:33:30

Same solution already given by Sreekanth G, Matt Le Fleur and others. And your version is worse because it doesn't convert back the result to a string.

@bibble triple 2019-03-30 21:49:23

but it doesnt have to thats for the person to decide what they want to do with the result

@ayaio 2019-03-30 21:52:00

I understand what you say. But the second part of my comment was just an addition to the first part, which was the real important part: this solution has already been given in other answers. Please don't post what has already been posted. Don't post duplicate content, that's all I'm saying. puts each letters of your string into arrrays is already the solution given by Sreekanth G and others. Literally the same.

@Cristik 2019-12-28 19:44:36

For a simple task like this one, the solution poses performance issues, as the whole contents of the string will be duplicated in memory.

@Sreekanth G 2019-03-15 06:03:14

Check this is 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])

@Noah Wilder 2018-12-17 21:59:38

Swift 4.2

This answer is ideal because it extends String and all of its Subsequences (Substring) in one extension

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

Usage

var str = "Hello, playground"

print(str[5...][...5][0])
// Prints ","

@Leo Dabus 2018-12-19 00:24:40

This is unnecessarily offsets both indexes (start and end) from the startIndex. You could simply offset the end index using the range.count and offset the start index

@Noah Wilder 2018-04-27 22:33:09

Get & Set Subscript (String & Substring) - Swift 4.2

Swift 4.2, Xcode 10

I based my answer off of @alecarlson's answer. The only big difference is you can get a Substring or a String returned (and in some cases, a single Character). You can also get and set the subscript. Lastly, mine is a bit more cumbersome and longer than @alecarlson's answer and as such, I suggest you put it in a source file.


Extension:

public extension String {
    public subscript (i: Int) -> Character {
        get {
            return self[index(startIndex, offsetBy: i)]
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ..< end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ... end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ..< end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> String {
        get {
            return "\(self[index(startIndex, offsetBy: i)])"
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            self.replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ..< end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ... end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ..< end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> Substring {
        get {
            return Substring("\(self[index(startIndex, offsetBy: i)])")
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
}
public extension Substring {
    public subscript (i: Int) -> Character {
        get {
            return self[index(startIndex, offsetBy: i)]
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }

    }
    public subscript (bounds: CountableRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ..< end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ... end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ..< end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }
    public subscript (i: Int) -> String {
        get {
            return "\(self[index(startIndex, offsetBy: i)])"
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ..< end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ... end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ..< end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> Substring {
        get {
            return Substring("\(self[index(startIndex, offsetBy: i)])")
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
}

@dfri 2017-10-25 20:42:37

Swift 4

Range and partial range subscripting using String's indices property

As variation of @LeoDabus nice answer, we may add an additional extension to DefaultBidirectionalIndices with the purpose of allowing us to fall back on the indices property of String when implementing the custom subscripts (by Int specialized ranges and partial ranges) for the latter.

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"

Thanks @LeoDabus for the pointing me in the direction of using the indices property as an(other) alternative to String subscripting!

Swift 4.2.

In Swift 4.2, DefaultBidirectionalIndices has been deprecated in favour of DefaultIndices.

@Leo Dabus 2017-10-25 20:51:34

the only disadvantage is CountableClosedRange will offset both indexes from the startIndex

@Leo Dabus 2018-03-26 23:38:17

stackoverflow.com/a/38215613/4573247 now extends StringProtocol to support Substrings as well

@Leo Dabus 2018-08-31 11:41:28

Swift 4.2 DefaultBidirectionalIndices has been renamed to DefaultIndices

@Leo Dabus 2018-08-31 15:37:30

Not yet. May be in 10-14 days from now. Are you coding on linux?

@dfri 2018-08-31 19:29:28

@LeoDabus I see. Yes mostly linux but not much Swift these days :/ I use swiftenv when I do, though, I guess it will be updated with 4.2 also somewhat soon then.

@Hamed 2017-01-18 15:51:45

Swift3

You can use subscript syntax to access the Character at a particular String index.

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

Visit https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html

or we can do a String Extension in Swift 4

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

USAGE:

let foo = "ABC123"
foo.getCharAtIndex(2) //C

@philippinedev 2014-11-27 06:43:53

Get the first letter:

first(str) // retrieve first letter

More here: http://sketchytech.blogspot.com/2014/08/swift-pure-swift-method-for-returning.html

@AkilRajdho 2018-03-27 18:23:39

Include this extension in your project

  extension String{
func trim() -> String
{
    return self.trimmingCharacters(in: NSCharacterSet.whitespaces)
}

var length: Int {
    return self.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])
}

func substring(fromIndex: Int, toIndex:Int)->String{
    let startIndex = self.index(self.startIndex, offsetBy: fromIndex)
    let endIndex = self.index(startIndex, offsetBy: toIndex-fromIndex)

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

An then use the function like this

let str = "Sample-String"

let substring = str.substring(fromIndex: 0, toIndex: 0) //returns S
let sampleSubstr = str.substring(fromIndex: 0, toIndex: 5) //returns Sample

@Harsh G. 2017-11-10 19:36:45

Swift 4

String(Array(stringToIndex)[index]) 

This is probably the best way of solving this problem one-time. You probably want to cast the String as an array first, and then cast the result as a String again. Otherwise, a Character will be returned instead of a String.

Example String(Array("HelloThere")[1]) will return "e" as a String.

(Array("HelloThere")[1] will return "e" as a Character.

Swift does not allow Strings to be indexed like arrays, but this gets the job done, brute-force style.

@Cristik 2019-12-28 19:47:19

Duplicating the whole string contents to another memory location is counter-performant, especially for large strings. We should not need extra memory allocations for simple tasks like direct memory access.

@Warif Akhand Rishi 2015-11-16 10:23:20

Swift 4

let str = "My String"

String at index

let index = str.index(str.startIndex, offsetBy: 3)
String(str[index])    // "S"

Substring

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)
String(str[startIndex...endIndex])     // "Strin"

First n chars

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[..<startIndex])    // "My "

Last n chars

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[startIndex...])    // "String"

Swift 2 and 3

str = "My String"

**String At Index **

Swift 2

let charAtIndex = String(str[str.startIndex.advancedBy(3)])  // charAtIndex = "S"

Swift 3

str[str.index(str.startIndex, offsetBy: 3)]

SubString fromIndex toIndex

Swift 2

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

Swift 3

str[str.index(str.startIndex, offsetBy: 3)...str.index(str.startIndex, offsetBy: 7)]

First n chars

let first2Chars = String(str.characters.prefix(2)) // first2Chars = "My"

Last n chars

let last3Chars = String(str.characters.suffix(3)) // last3Chars = "ing"

@George Maisuradze 2017-09-25 13:46:39

There's an alternative, explained in String manifesto

extension String : BidirectionalCollection {
    subscript(i: Index) -> Character { return characters[i] }
}

@Sulthan 2014-06-12 07:18:08

No indexing using integers, only using String.Index. Mostly with linear complexity. You can also create ranges from String.Index and get substrings using them.

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]

Note that you can't ever use an index (or range) created from one string to another string

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]

@zaph 2014-08-19 15:34:37

String indexs are unique to a string. This is because different strings may have different multi-unit UTF-16 Characters and/or at different positions so the UTF-16 unit indexs will not match, may fall beyond the end or point inside a multi-unit UTF-16 Character.

@Sulthan 2014-08-19 15:58:43

@Zaph That's obvious.

@zaph 2014-08-19 17:17:21

Explaning why you say: "sometimes it will crash or result in undefined behaviour". Perhaps better to say just don't do it because ...

@Aaron Brager 2014-10-25 04:41:50

@Sulthan .. is now ..< (in your assignment to range)

@Cajunluke 2014-10-28 19:37:40

On the shipping version of Swift, string[string.endIndex] results in EXC_BAD_INSTRUCTION apparently as string.endIndex is one place beyond the end of the string. string[string.endIndex-1] doesn't work as String.Index isn't IntegerConvertible. How do we get the last character of the string?

@David L 2014-12-14 07:11:17

@CajunLuke I know it's been a while since you posted this comment, but take a look at this answer. You can use var lastChar = string[string.endIndex.predecessor()]

@Daniele Ceglia 2017-05-29 12:32:06

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"

@Peter Kreinz 2017-04-11 22:13:47

Swift 3: another solution (tested in playground)

extension String {
    func substr(_ start:Int, length:Int=0) -> String? {
        guard start > -1 else {
            return nil
        }

        let count = self.characters.count - 1

        guard start <= count else {
            return nil
        }

        let startOffset = max(0, start)
        let endOffset = length > 0 ? min(count, startOffset + length - 1) : count

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

Usage:

let txt = "12345"

txt.substr(-1) //nil
txt.substr(0) //"12345"
txt.substr(0, length: 0) //"12345"
txt.substr(1) //"2345"
txt.substr(2) //"345"
txt.substr(3) //"45"
txt.substr(4) //"5"
txt.substr(6) //nil
txt.substr(0, length: 1) //"1"
txt.substr(1, length: 1) //"2"
txt.substr(2, length: 1) //"3"
txt.substr(3, length: 1) //"4"
txt.substr(3, length: 2) //"45"
txt.substr(3, length: 3) //"45"
txt.substr(4, length: 1) //"5"
txt.substr(4, length: 2) //"5"
txt.substr(5, length: 1) //nil
txt.substr(5, length: -1) //nil
txt.substr(-1, length: -1) //nil

@Matt Le Fleur 2017-04-11 09:44:37

Here's an extension you can use, working with Swift 3.1. A single index will return a Character, which seems intuitive when indexing a String, and a Range will return a 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]
    }
}

Some examples of the extension in action:

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. You could add an additional method to the above extension to return a String with a single character if wanted:

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

Note that then you would have to explicitly specify the type you wanted when indexing the string:

let c: Character = string[3] // Character "l"
let s: String = string[0]    // String "H"

@Cristik 2019-12-28 19:50:29

Creating an Array just to access an element seems like over-engineering, and also has performance costs as the string contents will have to be duplicated in memory.

@Jay Harris 2017-03-21 06:19:01

Allows Negative Indices

Its always useful not always having to write string[string.length - 1] to get the last character when using a subscript extension. This (Swift 3) extension allows for negative indices, Range and 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]
    }
}

How you can use it:

var text = "Hello World"

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

For the more thorough Programmer: Include a guard against empty Strings in this extension

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

subscript (r: Range<Int>) -> String {
    guard self.count != 0 else { return "" }
    ...
}

@Stephane Paquet 2016-11-19 17:36:25

Using characters would do the job. You can quickly convert the String to an array of characters that can be manipulated by the CharacterView methods.

Example:

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

(full CharacterView doc)

(tested in Swift 3)

@SoftDesigner 2015-07-07 09:53:17

If you see Cannot subscript a value of type 'String'... use this extension:

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

Source: http://oleb.net/blog/2014/07/swift-strings/

@John Pavley 2016-10-22 17:20:23

In Swift 3 without extensions to the String class, as simple as I can make it!

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

myCharacter is "3" in this example.

@Joseph Chen 2016-10-16 05:40:54

I wanted to point out that if you have a large string and need to randomly access many characters from it, you may want to pay the extra memory cost and convert the string to an array for better performance:

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

@Matt Le Fleur 2015-09-16 12:02:08

Swift 2.0 as of Xcode 7 GM Seed

var text = "Hello, world!"

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

For the nth character, replace 0 with n-1.

Edit: Swift 3.0

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


n.b. there are simpler ways of grabbing certain characters in the string

e.g. let firstChar = text.characters.first

@quemeful 2016-09-15 13:27:23

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

}

Usage

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

Helpful Programming Tips and Tricks (written by me)

Related Questions

Sponsored Content

18 Answered Questions

[SOLVED] Count the number occurrences of a character in a string

  • 2009-07-20 20:00:36
  • Mat
  • 928372 View
  • 931 Score
  • 18 Answer
  • Tags:   python string count

34 Answered Questions

[SOLVED] Split a String into an array in Swift?

17 Answered Questions

[SOLVED] #ifdef replacement in the Swift language

22 Answered Questions

[SOLVED] Remove last character from string. Swift language

  • 2014-06-09 14:21:09
  • Konstantin Cherkasov
  • 146151 View
  • 230 Score
  • 22 Answer
  • Tags:   string character swift

6 Answered Questions

39 Answered Questions

41 Answered Questions

[SOLVED] Get the length of a String

  • 2014-06-04 12:40:01
  • Scott Walter
  • 460109 View
  • 772 Score
  • 41 Answer
  • Tags:   swift string

4 Answered Questions

[SOLVED] Get the first character from values of array in Swift

Sponsored Content