【问题标题】:How to separate characters in String by whitespace with multiple strides?如何用多个跨步的空格分隔字符串中的字符?
【发布时间】:2020-08-07 23:55:40
【问题描述】:

我有一个工作函数,可以用空格分隔每个 n 字符,效果很好。

这里是代码(Swift 5):

extension String {
    /// Creates a new string, separating characters specified by stride lenght.
    /// - Parameters:
    ///   - stride: Desired stride lenght.
    ///   - separator: Character to be placed in between separations
    func separate(every stride: Int, with separator: Character) -> String {
        return String(self.enumerated().map { $0 > 0 && $0 % stride == 0 ? [separator, $1] : [$1] }.joined())
    }
}

这会像这样打印一个示例字符串 1234123412341234

1234 1234 1234 1234

现在,我如何将这个字符串 1234123412341234 与多个步长分开,例如在第 4 个字符之后设置空白,然后在第 6 个字符之后,然后在第 5 个字符之后设置,如下所示:

1234 123412 34123 4

【问题讨论】:

  • 您需要多通用的解决方案?或者您只是在处理固定大小的字符串和组?
  • 好吧,@Alexander-ReinstateMonica,我想有一个像我的代码示例中那样的函数,您可以在其中传递一个 [Int] 数组作为参数,这样您就可以有一个函数,其中您可以选择所需的步幅以及步幅的长度。我不希望只使用具有静态步幅的函数,例如 [4, 6, 5]

标签: swift string foundation


【解决方案1】:

我会这样做:

// Prints sequences of bools using 1/0s for easy reading
func p<S: Sequence>(_ 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<Bool, Int> {
    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<S: Sequence>(spans: S)
    -> LazySequence<FlattenSequence<LazyMapSequence<S, UnfoldSequence<Bool, Int>>>>
    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)

主要思想是我想要zip(self, spacePositions),以便获得self 的字符序列,以及一个告诉我是否应该在当前字符后附加一个空格的布尔值。

为了计算 spacePositions,我首先创建了一个函数,当给定 Int 输入 span 时,将返回 span falses 后跟 true。例如。 makeWindow(span: 3) 返回一个产生false, false, false, true 的序列。

从那里开始,只需为每个输入元素创建一个窗口,然后使用flatMap 将它们连接在一起。我懒惰地做这一切,所以我们实际上不需要存储所有这些重复的布尔值。

不过,我遇到了一个障碍。如果你输入[4, 6, 5],我习惯的输出是4字符,空格,6字符,空格,5字符,结束。字符串的其余部分丢失了,因为zip 生成的序列的长度等于两个输入中较短的长度。

为了解决这个问题,我在spans 输入上附加了Int.max。这样,空间位置为000010000001000001 ...now followed by Int.max falses

【讨论】:

  • 非常感谢 Alexander 抽出宝贵时间提供有效的解决方案和解释。这很有帮助:)
  • @Miki 如果您还有其他问题,请告诉我 :)
【解决方案2】:
func separate(text: String,every stride: [Int], with separator: Character)->String {
    var separatorLastPosition = 0 // This is the last separator position in text
    var myText = text
    if text.count < stride.reduce(0,+){
        return text //if your text length not enough for adding separator for all stride positions it will return the text without modifications.you can return error msg also
    }else{
        for (index, item) in stride.enumerated(){
           myText.insert(separator, at:myText.index(myText.startIndex, offsetBy: index == 0 ? item : separatorLastPosition+item))
           separatorLastPosition += item+1
        }
        return myText
    }
}

    print(separate(text: "12345678901234567890", every: [2,4,5,2], with: " "))
    //Result -- 12 3456 78901 23 4567890

【讨论】:

  • 谢谢,这就是我一直在寻找的
  • 哎呀,这是相当草率的 Swift 代码。我建议你改进一些事情:1)逗号和else周围的间距一致,2)不要迭代索引,使用enumerated(),3)这实际上不适用于OP的测试用例separate(text: "1234123412341234", every: [4, 6, 5], with: " "),它只返回return text 4) 有很多类似的变量,不清楚它们的作用,并引发了很多问题:index 是什么?它与j 有何不同?为什么j == 0 是特殊情况?
  • @Alexander-ReinstateMonica 先生,您能检查一下更新后的代码吗?
  • 1) 间距仍然是一团糟 2) separatorLastPosition 应该是 String.Index,而不是 Int。它应该从myText.startIndex 开始,并在每次循环迭代中得到提升。就目前而言,此代码不会在每个循环中执行O(n) 遍历字符串。 3) 返回text 并没有多大意义。最好是throwreturn nil
【解决方案3】:
func separateCharcters(numbers: String, every: inout [Int], character: Character) ->String{
    var counter = 0
    var numbersWithSpaces = ""

    for (_, number) in numbers.enumerated(){

        numbersWithSpaces.append(number)

        if !every.isEmpty{
            counter += 1
            if counter  == every.first!{
                numbersWithSpaces.append(character)
                every.removeFirst()
                counter = 0
            }
        }
    }
    return numbersWithSpaces
}
Test Case
var numberArray = [4, 6, 5]
separateCharcters(numbers: "1234123412341234", every: &numberArray, character: " ")
Return Result = "1234 123412 34123 4"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多