Как разделить символы в строке на пробел с несколькими шагами? - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть рабочая функция, которая разделяет каждый 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

Ответы [ 3 ]

1 голос
/ 24 апреля 2020
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
1 голос
/ 30 апреля 2020
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"
1 голос
/ 24 апреля 2020

Вот как я бы это сделал:

// 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 input span вернула бы span false с, за которыми следует true. Например, makeWindow(span: 3) возвращает последовательность, которая дает false, false, false, true.

. Оттуда просто нужно сделать один из этих windows для каждого элемента ввода и объединить их все вместе, используя flatMap. Я делаю это все лениво, так что нам на самом деле не нужно хранить все эти повторяющиеся логические значения.

Я попал в одну загадку. Если вы дадите ввод [4, 6, 5], я бы использовал вывод 4 символов, пробел, 6 символов, пробел, 5 символов, конец. Остальная часть строки была потеряна, потому что zip дает последовательность, длина которой равна длине более короткого из двух входов.

Чтобы исправить это, я добавляю Int.max к spans вход. Таким образом, позиции в пространстве будут 000010000001000001 ...now followed by Int.max falses.

...