How add separator to string at every N characters in swift?
Swift 5.2 • Xcode 11.4 or later
extension Collection {
func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence {
sequence(state: startIndex) { start in
guard start < endIndex else { return nil }
let end = index(start, offsetBy: maxLength, limitedBy: endIndex) ?? endIndex
defer { start = end }
return self[start.. }
}
func every(n: Int) -> UnfoldSequence {
sequence(state: startIndex) { index in
guard index < endIndex else { return nil }
defer { let _ = formIndex(&index, offsetBy: n, limitedBy: endIndex) }
return self[index]
}
}
var pairs: [SubSequence] { .init(unfoldSubSequences(limitedTo: 2)) }
}
extension StringProtocol where Self: RangeReplaceableCollection {
mutating func insert(separator: S, every n: Int) {
for index in indices.every(n: n).dropFirst().reversed() {
insert(contentsOf: separator, at: index)
}
}
func inserting(separator: S, every n: Int) -> Self {
.init(unfoldSubSequences(limitedTo: n).joined(separator: separator))
}
}
Testing
let str = "112312451"
let final0 = str.unfoldSubSequences(limitedTo: 2).joined(separator: ":")
print(final0) // "11:23:12:45:1"
let final1 = str.pairs.joined(separator: ":")
print(final1) // "11:23:12:45:1"
let final2 = str.inserting(separator: ":", every: 2)
print(final2) // "11:23:12:45:1\n"
var str2 = "112312451"
str2.insert(separator: ":", every: 2)
print(str2) // "11:23:12:45:1\n"
var str3 = "112312451"
str3.insert(separator: ":", every: 3)
print(str3) // "112:312:451\n"
var str4 = "112312451"
str4.insert(separator: ":", every: 4)
print(str4) // "1123:1245:1\n"
How do you split a string at every n-th character in Swift?
Implement this function
extension String {
func inserting(separator: String, every n: Int) -> String {
var result: String = ""
let characters = Array(self.characters)
stride(from: 0, to: characters.count, by: n).forEach {
result += String(characters[$0.. if $0+n < characters.count {
result += separator
}
}
return result
}
}
call it this way,
let str = "XQQ230IJFEKJLDSAIOUOIDSAUIFOPDSFE28"
let final = str.inserting(separator: " ", every: 8)
print(final)
Output will be like this,
XQQ230IJ FEKJLDSA IOUOIDSA UIFOPDSF E28
This will be generic solution if you want to add any character instead of space, it will work.
Swift format string with separator every n characters where n changes
The recursive approach is likely the most maintainable and flexible for this. It can be made fully configurable and can become an extension of the String type.
For example:
extension String
{
func group(by groupSize:Int=3, separator:String="-") -> String
{
if characters.count <= groupSize { return self }
let splitSize = min(max(2,characters.count-2) , groupSize)
let splitIndex = index(startIndex, offsetBy:splitSize)
return substring(to:splitIndex)
+ separator
+ substring(from:splitIndex).group(by:groupSize, separator:separator)
}
}
string.group(by:3)
How to add substring as separator to paragraph after every N words
You convert the string to an array, and then use map to add the separator:
extension String {
func add(separator: String, afterNWords: Int) -> String {
return split(separator: " ").enumerated().map { (index, element) in
index % afterNWords == afterNWords-1 ? "\(element) \(separator)" : String(element)
}.joined(separator: " ")
}
}
//Usage:
let result = paragraph.add(separator: "$$$$", afterNWords: 3)
Insert character after first N characters in Swift
You just need to anchor your regex pattern to the start of the string:
let regex = #"^(.{\#(every)})"#
How add separator to string at every N characters in swift?
Swift 5.2 • Xcode 11.4 or later
extension Collection {
func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence {
sequence(state: startIndex) { start in
guard start < endIndex else { return nil }
let end = index(start, offsetBy: maxLength, limitedBy: endIndex) ?? endIndex
defer { start = end }
return self[start.. }
}
func every(n: Int) -> UnfoldSequence {
sequence(state: startIndex) { index in
guard index < endIndex else { return nil }
defer { let _ = formIndex(&index, offsetBy: n, limitedBy: endIndex) }
return self[index]
}
}
var pairs: [SubSequence] { .init(unfoldSubSequences(limitedTo: 2)) }
}
extension StringProtocol where Self: RangeReplaceableCollection {
mutating func insert(separator: S, every n: Int) {
for index in indices.every(n: n).dropFirst().reversed() {
insert(contentsOf: separator, at: index)
}
}
func inserting(separator: S, every n: Int) -> Self {
.init(unfoldSubSequences(limitedTo: n).joined(separator: separator))
}
}
Testing
let str = "112312451"
let final0 = str.unfoldSubSequences(limitedTo: 2).joined(separator: ":")
print(final0) // "11:23:12:45:1"
let final1 = str.pairs.joined(separator: ":")
print(final1) // "11:23:12:45:1"
let final2 = str.inserting(separator: ":", every: 2)
print(final2) // "11:23:12:45:1\n"
var str2 = "112312451"
str2.insert(separator: ":", every: 2)
print(str2) // "11:23:12:45:1\n"
var str3 = "112312451"
str3.insert(separator: ":", every: 3)
print(str3) // "112:312:451\n"
var str4 = "112312451"
str4.insert(separator: ":", every: 4)
print(str4) // "1123:1245:1\n"
How to add substring as separator to paragraph after every N words
You convert the string to an array, and then use map to add the separator:
extension String {
func add(separator: String, afterNWords: Int) -> String {
return split(separator: " ").enumerated().map { (index, element) in
index % afterNWords == afterNWords-1 ? "\(element) \(separator)" : String(element)
}.joined(separator: " ")
}
}
//Usage:
let result = paragraph.add(separator: "$$$$", afterNWords: 3)
How to separate characters in String by whitespace with multiple strides?
Here's how I would do this:
// Prints sequences of bools using 1/0s for easy reading
func p(_ bools: S) where S.Element == Bool {
print(bools.map { $0 ? "1" : "0"}.joined())
}
// E.g. makeWindow(span: 3) returns 0001
func makeWindow(span: Int) -> UnfoldSequence {
return sequence(state: span) { state in
state -= 1
switch state {
case -1: return nil
case 0: return true
case _: return false
}
}
}
// E.g. calculateSpacePositions(spans: [4, 6, 5]) returns 000100000100001
func calculateSpacePositions(spans: S)
-> LazySequence>>>
where S.Element == Int {
return spans.lazy.flatMap(makeWindow(span:))
}
extension String {
func insertingSpaces(at spans: [Int]) -> String {
let spacePositions = calculateSpacePositions(spans: spans + [Int.max])
// p(spacePositions.prefix(self.count))
let characters = zip(inputString, spacePositions)
.flatMap { character, shouldHaveSpace -> [Character] in
return shouldHaveSpace ? [character, "_"] : [character]
}
return String(characters)
}
}
let inputString = "1234123412341234"
let result = inputString.insertingSpaces(at: [4, 6, 5])
print(result)
The main idea is that I want to zip(self, spacePositions)
, so that I obtain a sequence of the characters of self
, along with a boolean that tells me if I should append a space after the current character.
To calculate spacePositions
, I first started by making a function that when given an Int
input span
, would return span
false
s followed by a true
. E.g. makeWindow(span: 3)
returns a sequence that yields false, false, false, true
.
From there, it's just a matter of making one of these windows per element of the input, and joining them all together using flatMap
. I do this all lazily, so that we don't actually need to store all of these repeated booleans.
I hit one snag though. If you give the input [4, 6, 5]
, the output I would get used to be 4
characters, space, 6
characters, space, 5
characters, end. The rest of the string was lost, because zip
yields a sequence whose length is equal to the length of the shorter of the two inputs.
To remedy this, I append Int.max
on the spans
input. That way, the space positions are 000010000001000001 ...now followed by Int.max falses
.
Related Topics
Navigation Controller Push View Controller
Watchkit Extension - No Matching Provisioning Profiles Found
Didregisterforremotenotificationswithdevicetoken Not Called in Ios8, But Didregister...Settings Is
How to Use Auto Layout to Move Other Views When a View Is Hidden
Send Post Request Using Nsurlsession
Fade/Dissolve When Changing Uiimageview'S Image
How to Allow Didset to Be Called During Initialization in Swift
Download and Install an Ipa from Self Hosted Url on Ios
Is This Possible to Apply the Alternative Icon to the iOS Application
How to Detect iPhone Is on Silent Mode
Sprite Kit & Playing Sound Leads to App Termination
How to Get the Name of Image Picked Through Photo Library in Iphone