【问题标题】:How add separator to string at every N characters in swift?如何在swift中的每N个字符处为字符串添加分隔符?
【发布时间】:2016-03-31 00:02:01
【问题描述】:

我有一个包含二进制数字的字符串。如何将其分成数对?

假设字符串是:

let x = "11231245"

我想在每 2 个字符后添加一个分隔符,例如“:”(即冒号)。

我希望输出是:

"11:23:12:45"

我如何在 Swift 中做到这一点?

【问题讨论】:

  • 为了记录和您将来的利益,: 是一个“冒号”。 “逗号”表示,
  • 到目前为止您尝试过什么?请注意,您提供的唯一代码行实际上甚至不是有效代码

标签: ios string swift character


【解决方案1】:

Swift 5.2 • Xcode 11.4 或更高版本

extension Collection {
    func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
        sequence(state: startIndex) { start in
            guard start < self.endIndex else { return nil }
            let end = self.index(start, offsetBy: maxLength, limitedBy: self.endIndex) ?? self.endIndex
            defer { start = end }
            return self[start..<end]
        }
    }

    func every(n: Int) -> UnfoldSequence<Element,Index> {
        sequence(state: startIndex) { index in
            guard index < endIndex else { return nil }
            defer { index = self.index(index, offsetBy: n, limitedBy: endIndex) ?? endIndex }
            return self[index]
        }
    }

    var pairs: [SubSequence] { .init(unfoldSubSequences(limitedTo: 2)) }
}


extension StringProtocol where Self: RangeReplaceableCollection {
    mutating func insert<S: StringProtocol>(separator: S, every n: Int) {
        for index in indices.every(n: n).dropFirst().reversed() {
            insert(contentsOf: separator, at: index)
        }
    }
    func inserting<S: StringProtocol>(separator: S, every n: Int) -> Self {
        .init(unfoldSubSequences(limitedTo: n).joined(separator: separator))
    }
}


测试

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"

【讨论】:

  • @LeoDabus 这些扩展是你写的吗?如果是这样,你能帮我做些什么吗?我正在尝试插入“|”每 70 个字符,但前提是第 70 个字符是空格。如果不是,则向后大步直到找到空间。我基本上将它用作新的行生成器。我似乎无法弄清楚如何去做,我尝试了很多不同的方法。
  • 是的,我写了所有这些。随意发布您解决问题的方法以及新问题中出了什么问题,我会看看它。
  • @LeoDabus 太好了,看看这里。 stackoverflow.com/questions/43005306/…
  • @TheValyreanGroup 所以你想在第 9 个之后的每个空格中分割你的字符串?
  • 哦,是的......这很容易。我太笨了非常感谢您的帮助。祝你有美好的一天!
【解决方案2】:

我会选择这个紧凑的解决方案(在 Swift 4 中):

let s = "11231245"
let r = String(s.enumerated().map { $0 > 0 && $0 % 2 == 0 ? [":", $1] : [$1]}.joined())

您可以进行扩展并参数化步幅和分隔符,以便您可以将它用于您想要的每个值(在我的例子中,我使用它来转储 32 位空格操作的十六进制数据):

extension String {
    func separate(every stride: Int = 4, with separator: Character = " ") -> String {
        return String(enumerated().map { $0 > 0 && $0 % stride == 0 ? [separator, $1] : [$1]}.joined())
    }
}

在您的情况下,这会产生以下结果:

let x = "11231245"
print (x.separate(every:2, with: ":")

$ 11:23:12:45

【讨论】:

  • 我的 xcode 在声明函数时要求返回,如下所示: func separate(every stride: Int = 4, with separator: Character = " ") -> String {
  • 这不会编译。
  • @TruMan1:你用的是什么 Xcode 和 Swift 版本?
  • 对不起,我刚刚意识到我试图使用字符串作为分隔符。我喜欢你是一个班轮,实际上更容易理解(我想知道性能比较)。如何调整扩展以接受字符串作为分隔符?切换到字符串类型时出现的错误是:无法使用类型为 '(FlattenCollection)' 的参数列表调用类型为 'init(_:)' 的初始化程序
  • @StéphanedeLuca 您可以简单地使用 flatMap 代替 map 并加入 .init(enumerated().flatMap { $0 &gt; 0 &amp;&amp; $0 % stride == 0 ? [separator, $1] : [$1]})
【解决方案3】:

简洁明了,如果需要,可以添加一个或两个let

extension String {

    func separate(every: Int, with separator: String) -> String {
        return String(stride(from: 0, to: Array(self).count, by: every).map {
            Array(Array(self)[$0..<min($0 + every, Array(self).count)])
        }.joined(separator: separator))
    }
}

let a = "separatemepleaseandthankyou".separate(every: 4, with: " ")

a

单独费率,谢谢你

【讨论】:

    【解决方案4】:

    这是我在 swift 4 中的代码

    let x = "11231245"
    
    var newText = String()
        for (index, character) in x.enumerated() {
            if index != 0 && index % 2 == 0 {
                newText.append(":")
            }
            newText.append(String(character))
        }
        print(newText)
    

    输出 11:23:12:45

    【讨论】:

    • newText.append(character)
    【解决方案5】:

    Swift 5.3

        /// Adds a separator at every N characters
        /// - Parameters:
        ///   - separator: the String value to be inserted, to separate the groups. Default is " " - one space.
        ///   - stride: the number of characters in the group, before a separator is inserted. Default is 4.
        /// - Returns: Returns a String which includes a `separator` String at every `stride` number of characters.
        func separated(by separator: String = " ", stride: Int = 4) -> String {
            return enumerated().map { $0.isMultiple(of: stride) && ($0 != 0) ? "\(separator)\($1)" : String($1) }.joined()
        }
    

    【讨论】:

    • 这是一个非常棒的解决方案。我认为这是最快捷、最容易理解的解决方案。
    • 谢谢。我添加了一个小修复。这是一个额外的检查 - 因为我为第一个字符添加了一个额外的空格(0 是任何数字的倍数)。
    • 感谢@MihaiL,简单有效的解决方案。
    【解决方案6】:

    我对该代码的尝试是:

    func insert(seperator: String, afterEveryXChars: Int, intoString: String) -> String {
        var output = ""
        intoString.characters.enumerate().forEach { index, c in
            if index % afterEveryXChars == 0 && index > 0 {
                output += seperator
            }
            output.append(c)
        }
        return output
    }
    
    insert(":", afterEveryXChars: 2, intoString: "11231245")
    

    哪些输出

    11:23:12:45

    【讨论】:

    • 你介意我编辑你的代码吗?不需要使用计数器,可以使用 enumerate()。您还可以添加一个附加条件(索引 > 0)来添加分隔符,以便能够摆脱该 dropFirst 方法
    • intoString.characters.enumerate().forEach { index, c in if index % afterEveryXChars == 0 && index > 0 { ...
    • @LeoDabus 一点也不,继续 - 你还在玩它吗? :P
    • 不玩了。我对我的很满意 :) 只是为了让你知道如何使用 enumerate()
    【解决方案7】:
    let y = String(
        x.characters.enumerate().map() {
            $0.index % 2 == 0 ? [$0.element] : [$0.element, ":"]
        }.flatten()
    )
    

    【讨论】:

    • 该代码留下一个尾随 :,当且仅当您不在第一个字符时,尝试在 $0.element 前面添加 :
    • 只需添加 .flatten().dropLast()
    • 请求是“在每 2 个字符之后”。如果不需要尾随“:”,那么您的建议会做,即:$0.index &gt; 0 &amp;&amp; $0.index % 2 == 0 ? [":", $0.element] : [$0.element]
    • @LeoDabus,不,如果原始字符串长度为奇数,dropLast 将消耗有效负载字符。
    • @AntonBronnikov String(x.characters.enumerate().map() { $0.index % 2 == 1 ? [$0.element] : [":",$0.element] }。 flatten().dropFirst())
    【解决方案8】:

    Swift 4.2.1 - Xcode 10.1

    extension String {
    
        func insertSeparator(_ separatorString: String, atEvery n: Int) -> String {
            guard 0 < n else { return self }
            return self.enumerated().map({String($0.element) + (($0.offset != self.count - 1 && $0.offset % n ==  n - 1) ? "\(separatorString)" : "")}).joined()
        }
    
        mutating func insertedSeparator(_ separatorString: String, atEvery n: Int) {
            self = insertSeparator(separatorString, atEvery: n)
        }
    }
    

    用法

    let testString = "11231245"
    
    let test1 = testString.insertSeparator(":", atEvery: 2)
    print(test1) // 11:23:12:45
    
    var test2 = testString
    test2.insertedSeparator(",", atEvery: 3)
    print(test2) // 112,312,45    
    

    【讨论】:

      【解决方案9】:

      插入分隔符的简单一行代码(Swift 4.2):-

      let testString = "123456789"
      
      let ansTest = testString.enumerated().compactMap({ ($0 > 0) && ($0 % 2 == 0) ? ":\($1)" : "\($1)" }).joined() ?? ""
      print(ansTest) // 12:34:56:78:9
      

      【讨论】:

        【解决方案10】:

        我来晚了,但我喜欢像这样使用正则表达式:

        extension String {
            func separating(every: Int, separator: String) -> String {
                let regex = #"(.{\#(every)})(?=.)"#
                return self.replacingOccurrences(of: regex, with: "$1\(separator)", options: [.regularExpression])
            }
        }
        
        "111222333".separating(every: 3, separator: " ")
        

        输出:

        "111 222 333"
        

        【讨论】:

        • 如果我们想用字符串作为分隔符怎么办?
        【解决方案11】:
        extension String{
        
        func separate(every: Int) -> [String] {
            return stride(from: 0, to: count, by: every).map {
                let ix0 = index(startIndex, offsetBy: $0);
                let ix1 = index(after:ix0);
                if ix1 < endIndex {
                    return String(self[ix0...ix1]);
                }else{
                    return String(self[ix0..<endIndex]);
                }
            }
        }
        

        /// 或 O(1) 实现(不计)

        func separate(every: Int) -> [String] {
            var parts:[String] = [];
            var ix1 = startIndex;
            while ix1 < endIndex {
                let ix0 = ix1;
                var n = 0;
                while ix1 < endIndex && n < every {
                    ix1 = index(after: ix1);
                    n += 1;
                }
                parts.append(String(self[ix0..<ix1]));
            }
            return parts;
        }
        
        "asdf234sdf".separate(every: 2).joined(separator: ":");
        

        【讨论】:

          【解决方案12】:

          一个简单的字符串扩展,不需要原始字符串是步长(增量)的倍数:

          extension String {
              func inserted(_ newElement: Character,atEach increment:Int)->String {
                  var newStr = self
          
                  for indx in stride(from: increment, to: newStr.count, by: increment).reversed() {
                      let index = String.Index(encodedOffset: indx)
                      newStr.insert(newElement, at: index)
                  }
          
                  return newStr
              }
           }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-08-13
            • 2023-02-25
            • 2022-01-18
            • 2015-12-04
            • 2022-01-15
            相关资源
            最近更新 更多