0

junior developer here. I am currently trying to achieve a substring that is split every n characters of a String.

This is my code for the function

public func split(every: Int) -> [String] {
    var result = [String]()

    for i in stride(from: 0, to: self.count, by: every) {
        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
}

The above code works as expected. But there is one lacking from the code above, which is the word wrapping. Here is the sample String

let itemName = "Japanese Matcha SM w RB -L Special Edition And Americano MS w Brown Sugar Limited Edition"
print(itemName.split(every: 26))

The result will be

["Japanese Matcha SM w RB -L", " Special Edition And Ameri", "cano MS w Brown Sugar Limi", "ted Edition"]

Notice the

[" Special Edition And Ameri"], ["cano MS w Brown Sugar Limi"]

I am trying to figure out how to do the word wrap algorithm based on every n character, but couldn't find any clue.

For example, from above case, how to generate the array becomes,

[" Special Edition And"], ["Americano MS w Brown"], ["Sugar"]

So as you can see, the algorithm might check whether every n characters has a word that is being cut out (dynamic check based on the n characters), hence will move the cut word into the next array.

So in that case, the algorithm will cleverly bypass the every n character, might be less, but not more than n characters, if there is any word not being wrapped.

Is my explanation clear? Can anyone guide me please? Thanks

Alvin
  • 529
  • 1
  • 8
  • 19
  • 4
    Well, your algorithm does exactly what you describe it should do: splits a String on every n-th character. Splitting on words is a completely different problem that's also contradicting splitting on every n-th character. So what is it that you are trying to achieve? – Dávid Pásztor May 22 '19 at 10:43
  • Your code do what you tel it to do. But if you wanna remove front and last spaces you may have write a loop function by your self. Eg. get first index check for space, if so advanced by one and check for space until you got a letter. Then add 26 to that index and check last space, etc. it’s not as hard as it sounds – RJE May 22 '19 at 10:50
  • Hello David, thanks for the respond. I have edited the question :) – Alvin May 22 '19 at 10:51
  • And what should the algorithm do when a specific word longer than the number of maximum characters allowed? – Dávid Pásztor May 22 '19 at 10:56
  • Use `enumerateSubstrings()` with the `.byWords` option ([example](https://stackoverflow.com/a/29668468)), count the characters in each substring, and decide when to start a new chunk. – Martin R May 22 '19 at 10:58
  • @DávidPásztor, if the last world already exceed the n characters, then it will be moved on to the next array. Further explanation has been added to the question. Thanks – Alvin May 22 '19 at 11:02

2 Answers2

1

This is some simple implementation of this algorithm, you can start with that. First we cut string by words, then add them to temporary string until we meet characters limit.

let itemName = "Japanese Matcha SM w RB -L Special Edition And Americano MS w Brown Sugar Limited Edition"

let table = itemName.split(separator: " ")

let limit = 26
var tempString = ""

var finalResult: [String] = []

for item in table {
    tempString += item + " "

    if tempString.count >= limit {
        finalResult.append(tempString)
        tempString = ""
    }
}

print(finalResult)
Lu_
  • 2,577
  • 16
  • 24
0

How about this?

extension String {
    func split(every: Int) -> [String] {
        var result = [String]()
        let words = self.split(separator: " ")
        var line = String(words.first!)

        words.dropFirst().forEach { word in
            let word = " " + String(word)
            if line.count + word.count <= every {
                line.append(word)
            } else {
                result.append(line)
                line = word
            }
        }
        result.append(line)
        return result
    }
}
pompopo
  • 929
  • 5
  • 10