Let's say I have a variable that contains a string
var someString = "@@@@@@@@@@"
and I'd like to insert a "#" symbol for every 1-3 characters in the string, so basically I wanna create something like this:
var someString = "@@#@#@@@#@#@@#@"
How can I achieve this in Swift?
michelf
(Michel Fortin)
2
Here's one way:
var currentIndex = someString.startIndex
var counter: Int = .random(in: 1...3)
while currentIndex != someString.endIndex {
if counter == 0 {
someString.insert("#", at: currentIndex)
someString.formIndex(after: ¤tIndex) // skip newly inserted character
counter = .random(in: 1...3) // restart counter
} else {
counter -= 1
}
someString.formIndex(after: ¤tIndex) // go to next character
}
1 Like
Karl
(👑🦆)
3
I'm not sure if that works. Crashes on my raspberry pi, but it has spotty unicode support anyway:
var someString = "@@@@@@@@@@@@@@@@@@@@@@@@@@"
print(someString)
var currentIndex = someString.startIndex
var counter: Int = .random(in: 1...3)
while currentIndex != someString.endIndex {
if counter == 0 {
someString.insert("😀", at: currentIndex)
someString.formIndex(after: ¤tIndex) // skip newly inserted character
counter = .random(in: 1...3) // restart counter
} else {
counter -= 1
}
someString.formIndex(after: ¤tIndex) // go to next character
}
print(someString)
@@@@@@@@@@@@@@@@@@@@@@@@@@
Fatal error: file /home/buildSwiftOnARM/swift/stdlib/public/core/UnicodeHelpers.swift, line 142
Current stack trace:
Stack dump:
0. Program arguments: /usr/bin/swift -frontend -interpret coll.swift -disable-objc-interop -color-diagnostics -module-name coll
Illegal instruction
Also, there's an off-by-one error. Sometimes it has strings of 4 @s.
I can't think of a better way to do it right now, though.
1 Like
That gave me exactly what I wanted! You're a lifesaver! Thanks so much!!
michelf
(Michel Fortin)
5
Ah yes. Can't rely on the index to still work after someString.insert:
Calling this method invalidates any existing indices for use with this string.
So the above code is prone to crash, even though it might not crash every time.
This one should be correct since it avoids mutating the string while iterating on it:
var slices: [Substring] = []
var beginIndex = someString.startIndex
var currentIndex = someString.startIndex
var counter: Int = .random(in: 0..<3)
while currentIndex != someString.endIndex {
if counter == 0 {
slices.append(someString[beginIndex..<currentIndex])
beginIndex = currentIndex // starting new slice at current index
counter = .random(in: 0..<3)
} else {
counter -= 1
}
someString.formIndex(after: ¤tIndex) // go to next character
}
slices.append(someString[beginIndex..<currentIndex])
someString = slices.joined(separator: "#")
4 Likes
extension String {
func split<Lengths: Sequence>(toLengths lengths: Lengths) -> [Substring] where Lengths.Element == Int {
var substrings: [Substring] = []
var remainingString = self[...]
for length in lengths {
let prefix = remainingString.prefix(length)
if prefix.count == 0 { break }
substrings.append(prefix)
remainingString = remainingString.dropFirst(length)
}
return substrings
}
}
let someString = "abcdefghijklmnopqrstuvwxyz"
let lengths = sequence(first: Int.random(in: 1...3)) { _ in Int.random(in: 1...3) }
print(someString.split(toLengths: lengths).joined(separator: "#"))
2 Likes