Split a string into groups with a specific length

How can I split a given String in Swift into groups with a given length, counting from right to left?

For example, I have the string 123456789 and the length of the group 3. The string should be divided into 3 groups: 123 , 456 , 789 . String 1234567 will be split into 1 , 234 , 567

So, can you write some good code in Swift:

 func splitedString(string: String, length: Int) -> [String] { } 

BTW tried the split() function, but as I understand it, it only works with finding the character

+7
source share
10 answers

Just to add your entry to this very eventful competition ( SwiftStub ):

 func splitedString(string: String, length: Int) -> [String] { var result = [String]() for var i = 0; i < string.characters.count; i += length { let endIndex = string.endIndex.advancedBy(-i) let startIndex = endIndex.advancedBy(-length, limit: string.startIndex) result.append(string[startIndex..<endIndex]) } return result.reverse() } 

Or, if you feel functionality-y:

 func splitedString2(string: String, length: Int) -> [String] { return 0.stride(to: string.characters.count, by: length) .reverse() .map { i -> String in let endIndex = string.endIndex.advancedBy(-i) let startIndex = endIndex.advancedBy(-length, limit: string.startIndex) return string[startIndex..<endIndex] } } 
+2
source

This is what I came up with from my head. I am sure there is a better way to do this, so I would advise you to keep trying.

 func splitedString(string: String, length: Int) -> [String] { var groups = [String]() var currentGroup = "" for index in string.startIndex..<string.endIndex { currentGroup.append(string[index]) if currentGroup.characters.count == 3 { groups.append(currentGroup) currentGroup = "" } } if currentGroup.characters.count > 0 { groups.append(currentGroup) } return groups } 

Here are my tests

 let firstString = "123456789" let groups = splitedString(firstString, length: 3) // Returned ["123", "456", "789"] let secondString = "1234567" let moreGroups = splitedString(secondString, length: 3) // Returned ["123", "456", "7"] 
+1
source

Here is the version using NSRegularExpressions

 func splitedString(string: String, length: Int) -> [String] { var groups = [String]() let regexString = "(\\d{1,\(length)})" do { let regex = try NSRegularExpression(pattern: regexString, options: .CaseInsensitive) let matches = regex.matchesInString(string, options: .ReportCompletion, range: NSMakeRange(0, string.characters.count)) let nsstring = string as NSString matches.forEach { let group = nsstring.substringWithRange($0.range) as String groups.append(group) } } catch let error as NSError { print("Bad Regex Format = \(error)") } return groups } 
+1
source

Here is another version with functional programming.

 extension String{ func splitedString(length: Int) -> [String]{ guard length > 0 else { return [] } let range = 0..<((characters.count+length-1)/length) let indices = range.map{ length*$0..<min(length*($0+1),characters.count) } return indices .map{ characters.reverse()[$0.startIndex..<$0.endIndex] } .map( String.init ) } } "1234567890".splitedString(3) 
+1
source

Swift 4

I think the extension method is more useful.

 extension String{ public func splitedBy(length: Int) -> [String] { var result = [String]() for i in stride(from: 0, to: self.characters.count, by: length) { let endIndex = self.index(self.endIndex, offsetBy: -i) let startIndex = self.index(endIndex, offsetBy: -length, limitedBy: self.startIndex) ?? self.startIndex result.append(String(self[startIndex..<endIndex])) } return result.reversed() } } 

usage example:

 Swift.debugPrint("123456789".splitedBy(length: 4)) // Returned ["1", "2345", "6789"] 
+1
source

Swift 4

I adapted the answer provided by cafedeichi to work from left to right or from right to left, depending on the function parameter, to make it more universal.

 extension String { /// Splits a string into groups of 'every' n characters, grouping from left-to-right by default. If 'backwards' is true, right-to-left. public func split(every: Int, backwards: Bool = false) -> [String] { var result = [String]() for i in stride(from: 0, to: self.count, by: every) { switch backwards { case true: let endIndex = self.index(self.endIndex, offsetBy: -i) let startIndex = self.index(endIndex, offsetBy: -every, limitedBy: self.startIndex) ?? self.startIndex result.insert(String(self[startIndex..<endIndex]), at: 0) case false: let startIndex = self.index(self.startIndex, offsetBy: i) let endIndex = self.index(startIndex, offsetBy: every, limitedBy: self.endIndex) ?? self.endIndex result.append(String(self[startIndex..<endIndex])) } } return result } } 

Example:

 "abcde".split(every: 2) // ["ab", "cd", "e"] "abcde".split(every: 2, backwards: true) // ["a", "bc", "de"] "abcde".split(every: 4) // ["abcd", "e"] "abcde".split(every: 4, backwards: true) // ["a", "bcde"] 
+1
source

I did something like this, couldn't create anything better, but its result matches the question:

 func splitedString(string: String, lenght: Int) -> [String] { var result = [String](), count = 0, line = "" for c in string.characters.reverse() { count++; line.append(c) if count == lenght {count = 0; result.append(String(line.characters.reverse())); line = ""} } if !line.isEmpty {result.append(String(line.characters.reverse()))} return result.reverse() } 
0
source

Probably a more elegant solution, but it works:

 func splitedString(string: String, length: Int) -> [String] { let string = Array(string.characters) let firstGroupLength = string.count % length var result: [String] = [] var group = "" if firstGroupLength > 0 { for i in 0..<firstGroupLength { group.append(string[i]) } result.append(String(group)) group = "" } for i in firstGroupLength..<string.count { group.append(string[i]) if group.characters.count == length { result.append(group) group = "" } } return result } splitedString("abcdefg", length: 2) // ["a", "bc", "de", "fg"] splitedString("1234567", length: 3) // ["1", "234", "567"] 
0
source

Another solution using substrings:

 func splitStringByIntervals(str: String, interval: Int) -> [String] { let st = String(str.characters.reverse()) let length = st.characters.count var groups = [String]() for (var i = 0; i < length; i += interval) { groups.append((st as NSString).substringWithRange(NSRange(location: i, length: min(interval, length - i)))) } return groups.map{ String($0.characters.reverse())}.reverse() } 

Output for:

 for element in splitStringByIntervals("1234567", interval: 3) { print(element) } 

is an:

 1 234 567 
0
source
 func split(every length:Int) -> [Substring] { guard length > 0 && length < count else { return [suffix(from:startIndex)] } return (0 ... (count - 1) / length).map { dropFirst($0 * length).prefix(length) } } func split(backwardsEvery length:Int) -> [Substring] { guard length > 0 && length < count else { return [suffix(from:startIndex)] } return (0 ... (count - 1) / length).map { dropLast($0 * length).suffix(length) }.reversed() } 

tests:

  XCTAssertEqual("0123456789".split(every:2), ["01", "23", "45", "67", "89"]) XCTAssertEqual("0123456789".split(backwardsEvery:2), ["01", "23", "45", "67", "89"]) XCTAssertEqual("0123456789".split(every:3), ["012", "345", "678", "9"]) XCTAssertEqual("0123456789".split(backwardsEvery:3), ["0", "123", "456", "789"]) XCTAssertEqual("0123456789".split(every:4), ["0123", "4567", "89"]) XCTAssertEqual("0123456789".split(backwardsEvery:4), ["01", "2345", "6789"]) 
0
source

All Articles