Skip to content

Instantly share code, notes, and snippets.

@laacz
Last active September 23, 2020 22:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laacz/2c9776ca983ebec419950d6588615b78 to your computer and use it in GitHub Desktop.
Save laacz/2c9776ca983ebec419950d6588615b78 to your computer and use it in GitHub Desktop.
String access (set AND get) by int indices or ranges in Swift 5.
/**
*
* Since Swift has no concept of real world String uses, I just had to make this extension.
* With this extension you can set and get following:
*
* Access String by Int index:
* let second = string[1]
*
* Set value by index or range:
* string[1] = "a"
* string[1] = "asdf" // Yep, even this works
* string[1...2]
* string[1..<2]
* string[1...]
* string[...2]
* string[..<2]
*
*/
extension String {
// Covers string[index]
subscript (_ idx: Int) -> String {
get {
return String(self[index(startIndex, offsetBy: idx)])
}
set (newValue) {
replaceSubrange(index(startIndex, offsetBy: idx)..<index(startIndex, offsetBy: idx + 1), with: newValue)
}
}
// Covers string[start..<end]
subscript (_ range: Range<Int>) -> String {
get {
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(startIndex, offsetBy: range.upperBound)
return String(self[start...end])
}
set (newValue) {
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(startIndex, offsetBy: range.upperBound)
if (range.lowerBound >= count) {
self += newValue
} else {
replaceSubrange(start...end, with: newValue)
}
}
}
// Covers string[start...end]
subscript (_ range: ClosedRange<Int>) -> String {
get {
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(startIndex, offsetBy: range.upperBound)
return String(self[start...end])
}
set (newValue) {
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(startIndex, offsetBy: range.upperBound)
if (range.lowerBound >= count) {
self += newValue
} else {
replaceSubrange(start...end, with: newValue)
}
}
}
// Covers string[start...]
subscript (_ range: PartialRangeFrom<Int>) -> String {
get {
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(startIndex, offsetBy: count-1)
return String(self[start...end])
}
set (newValue) {
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(startIndex, offsetBy: count-1)
if (range.lowerBound >= count) {
self += newValue
} else {
replaceSubrange(start...end, with: newValue)
}
}
}
// Covers string[...end]
subscript (_ range: PartialRangeThrough<Int>) -> String {
get {
let start = index(startIndex, offsetBy: 0)
let end = index(startIndex, offsetBy: range.upperBound)
return String(self[start...end])
}
set (newValue) {
let start = index(startIndex, offsetBy: 0)
let end = index(startIndex, offsetBy: range.upperBound)
replaceSubrange(start...end, with: newValue)
}
}
// Covers string[..<end]
subscript (_ range: PartialRangeUpTo<Int>) -> String {
get {
let start = index(startIndex, offsetBy: 0)
let end = index(startIndex, offsetBy: range.upperBound)
return String(self[start...end])
}
set (newValue) {
let start = index(startIndex, offsetBy: 0)
let end = index(startIndex, offsetBy: range.upperBound)
replaceSubrange(start...end, with: newValue)
}
}
}
var string = "I'm a string";
assert(string == "I'm a string")
string[1] = " a"
assert(string == "I am a string")
string[1...3] = "'m not"
assert(string == "I'm not a string")
string[9..<9] = " particular "
assert(string == "I'm not a particular string")
string[...2] = "I am"
assert(string == "I am not a particular string")
string[28...] = "! Or am I?"
assert(string == "I am not a particular string! Or am I?")
string[..<3] = "I'm"
assert(string == "I'm not a particular string! Or am I?")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment