如何将字符串拆分为相等长度的子字符串

时间:2015-08-25 19:16:24

标签: string swift swift2

所以

split("There are fourty-eight characters in this string", 20)

应该返回

["There are fourty-eig", "ht characters in thi","s string"]

如果我使用currentIndex = string.startIndex然后尝试提前()它比string.endIndex更远,我得到"致命错误:无法递增endIndex"在我检查我的currentIndex<之前string.endIndex所以下面的代码不起作用

var string = "12345"
var currentIndex = string.startIndex
currentIndex = advance(currentIndex, 6)
if currentIndex > string.endIndex {currentIndex = string.endIndex}

9 个答案:

答案 0 :(得分:22)

我刚刚在SO上回答了类似的问题,并认为我可以提供更简洁的解决方案:

Swift 2

String res[] = a.split(" ");
int n = Integer.parseInt(res[0]);

Swift 3

func split(str: String, _ count: Int) -> [String] {
    return 0.stride(to: str.characters.count, by: count).map { i -> String in
        let startIndex = str.startIndex.advancedBy(i)
        let endIndex   = startIndex.advancedBy(count, limit: str.endIndex)
        return str[startIndex..<endIndex]
    }
}

Swift 4

更改为func split(_ str: String, _ count: Int) -> [String] { return stride(from: 0, to: str.characters.count, by: count).map { i -> String in let startIndex = str.index(str.startIndex, offsetBy: i) let endIndex = str.index(startIndex, offsetBy: count, limitedBy: str.endIndex) ?? str.endIndex return str[startIndex..<endIndex] } } 循环以提高效率,并按流行请求制作String的扩展名:

while

答案 1 :(得分:10)

只需一次通过字符序列即可轻松解决此问题:

Swift 2.2

extension String {
    func splitByLength(length: Int) -> [String] {
        var result = [String]()
        var collectedCharacters = [Character]()
        collectedCharacters.reserveCapacity(length)
        var count = 0

        for character in self.characters {
            collectedCharacters.append(character)
            count += 1
            if (count == length) {
                // Reached the desired length
                count = 0
                result.append(String(collectedCharacters))
                collectedCharacters.removeAll(keepCapacity: true)
            }
        }

        // Append the remainder
        if !collectedCharacters.isEmpty {
            result.append(String(collectedCharacters))
        }

        return result
    }
}

let foo = "There are fourty-eight characters in this string"
foo.splitByLength(20)

Swift 3.0

extension String {
    func splitByLength(_ length: Int) -> [String] {
        var result = [String]()
        var collectedCharacters = [Character]()
        collectedCharacters.reserveCapacity(length)
        var count = 0

        for character in self.characters {
            collectedCharacters.append(character)
            count += 1
            if (count == length) {
                // Reached the desired length
                count = 0
                result.append(String(collectedCharacters))
                collectedCharacters.removeAll(keepingCapacity: true)
            }
        }

        // Append the remainder
        if !collectedCharacters.isEmpty {
            result.append(String(collectedCharacters))
        }

        return result
    }
}

let foo = "There are fourty-eight characters in this string"
foo.splitByLength(20)

由于String是一种非常复杂的类型,因此范围和索引可能具有不同的计算成本,具体取决于视图。这些细节仍在不断发展,因此上述一次性解决方案可能是更安全的选择。

希望这有帮助

答案 2 :(得分:3)

您不得使用超出字符串大小的范围。以下方法将演示如何执行此操作:

extension String {
    func split(len: Int) -> [String] {
        var currentIndex = 0
        var array = [String]()
        let length = self.characters.count
        while currentIndex < length {
            let startIndex = self.startIndex.advancedBy(currentIndex)
            let endIndex = startIndex.advancedBy(len, limit: self.endIndex)
            let substr = self.substringWithRange(Range(start: startIndex, end: endIndex))
            array.append(substr)
            currentIndex += len
        }
        return array
    }
}

<强>用法:

"There are fourty-eight characters in this string".split(20)
//output: ["There are fourty-eig", "ht characters in thi", "s string"]

"⛵".split(3)
//output: ["", "", "⛵"]

编辑: 更新了使用Xcode 7 beta 6的答案。advance方法已不复存在,取而代之的是advancedBy的{​​{1}}实例方法。在这种情况下,Index版本特别有用。

答案 3 :(得分:3)

字符串扩展基于&#34; Code Different&#34;回答:

Swift 3/4/5

extension String {
    func components(withLength length: Int) -> [String] {
        return stride(from: 0, to: self.characters.count, by: length).map {
            let start = self.index(self.startIndex, offsetBy: $0)
            let end = self.index(start, offsetBy: length, limitedBy: self.endIndex) ?? self.endIndex
            return self[start..<end]
        }
    }
}

用法

let str = "There are fourty-eight characters in this string"
let components = str.components(withLength: 20)

答案 4 :(得分:3)

Swift 5 ,基于@Ondrej Stocek解决方案

extension String {
    func components(withMaxLength length: Int) -> [String] {
        return stride(from: 0, to: self.count, by: length).map {
            let start = self.index(self.startIndex, offsetBy: $0)
            let end = self.index(start, offsetBy: length, limitedBy: self.endIndex) ?? self.endIndex
            return String(self[start..<end])
        }
    }
}

答案 5 :(得分:2)

endIndex不是有效索引;它比有效范围多一个。

答案 6 :(得分:2)

如果你想以一定的长度分割一个字符串,你可以使用这个字符串扩展名,但也要考虑单词:

Swift 4:

import ast
new_data = ast.literal_eval(status)[0]

这是对 Matteo Piombo 上述答案的修改。

用法

['0', '2', '3', '5']

答案 7 :(得分:1)

我的字符数组解决方案:

func split(text: String, count: Int) -> [String] {
    let chars = Array(text)
    return stride(from: 0, to: chars.count, by: count)
        .map { chars[$0 ..< min($0 + count, chars.count)] }
        .map { String($0) }
}

或者您可以对带有 Substring 的大字符串使用更优化的变体:

func split(text: String, length: Int) -> [Substring] {
    return stride(from: 0, to: text.count, by: length)
        .map { text[text.index(text.startIndex, offsetBy: $0)..<text.index(text.startIndex, offsetBy: min($0 + length, text.count))] }
}

答案 8 :(得分:0)

这里是一个版本,可以在以下情况下使用:

  • 给定的行长度为0或更小
  • 输入为空
  • 一行的最后一个单词不适合:该单词被换成新行
  • 一行的最后一个单词长于行长:单词被剪切并部分包裹
  • 一行的最后一个单词比多行长:该单词被剪切和包装多次。
extension String {

    func ls_wrap(maxWidth: Int) -> [String] {
        guard maxWidth > 0 else {
            Logger.logError("wrap: maxWidth too small")
            return []
        }
        let addWord: (String, String) -> String = { (line: String, word: String) in
            line.isEmpty
                ? word
                : "\(line) \(word)"
        }
        let handleWord: (([String], String), String) -> ([String], String) = { (arg1: ([String], String), word: String) in
            let (acc, line): ([String], String) = arg1
            let lineWithWord: String = addWord(line, word)
            if lineWithWord.count <= maxWidth { // 'word' fits fine; append to 'line' and continue.
                return (acc, lineWithWord)
            } else if word.count > maxWidth { // 'word' doesn't fit in any way; split awkwardly.
                let splitted: [String] = lineWithWord.ls_chunks(of: maxWidth)
                let (intermediateLines, lastLine) = (splitted.ls_init, splitted.last!)
                return (acc + intermediateLines, lastLine)
            } else { // 'line' is full; start with 'word' and continue.
                return (acc + [line], word)
            }
        }
        let (accLines, lastLine) = ls_words().reduce(([],""), handleWord)
        return accLines + [lastLine]
    }
    
    // stolen from https://stackoverflow.com/questions/32212220/how-to-split-a-string-into-substrings-of-equal-length
    func ls_chunks(of length: Int) -> [String] {
        var startIndex = self.startIndex
        var results = [Substring]()
        while startIndex < self.endIndex {
            let endIndex = self.index(startIndex, offsetBy: length, limitedBy: self.endIndex) ?? self.endIndex
            results.append(self[startIndex..<endIndex])
            startIndex = endIndex
        }
        return results.map { String($0) }
    }
    
    // could be improved to split on whiteSpace instead of only " " and "\n"
    func ls_words() -> [String] {
        return split(separator: " ")
            .flatMap{ $0.split(separator: "\n") }
            .map{ String($0) }
    }
}

extension Array {
    
    var ls_init: [Element] {
        return isEmpty
            ? self
            : Array(self[0..<count-1])
    }
}