2015-10-23 14 views
6

Jak mogę podzielić dany String w Swift na grupy o zadanej długości, czytając od prawej do lewej?Podziel ciąg na grupy o określonej długości

Na przykład, mieć ciąg 123456789 i grupy długość 3. łańcuch powinien być podzielony na 3 grupy: 123, 456, 789. String 1234567 zostanie podzielony na 1, 234, 567

Tak, można napisać piękny kod SWIFT:

func splitedString(string: String, length: Int) -> [String] { 

} 

BTW próbowałem funkcji split(), ale jak rozumiem to działa tylko ze znalezieniem jakiś symbol

+0

Jaki jest cel i jakie są ograniczenia? Czy próbujesz sformatować reprezentacje liczb, np. "10000" staje się "10 000", przez przypadek? – Moritz

+0

@EricD. Nie, 'NSNumberFormatter' nie jest moim przypadkiem. Po prostu chcę wiedzieć, czy mogę zrealizować tę funkcję za pomocą funkcji 'split()' lub jakiegoś innego fajnego rozwiązania. – katleta3000

+0

Zauważ dokładnie to samo (ponieważ * last * chunk jest obcięty, a nie pierwszy, jak w twoim przykładzie), ale może służyć jako punkt wyjścia: stackoverflow.com/a/28560013/1187415. –

Odpowiedz

2

Wystarczy dodać swój wpis do tego bardzo zatłoczonym konkursu (SwiftStub):

func splitedString(string: String, length: Int) -> [String] { 
    var result = [String]() 

    for var i = 0; i < string.characters.count; i += length { 
     let endIndex = string.endIndex.advancedBy(-i) 
     let startIndex = endIndex.advancedBy(-length, limit: string.startIndex) 
     result.append(string[startIndex..<endIndex]) 
    } 

    return result.reverse() 
} 

Albo jeśli czujesz funkcjonalno-y:

func splitedString2(string: String, length: Int) -> [String] { 
    return 0.stride(to: string.characters.count, by: length) 
     .reverse() 
     .map { 
      i -> String in 
      let endIndex = string.endIndex.advancedBy(-i) 
      let startIndex = endIndex.advancedBy(-length, limit: string.startIndex) 
      return string[startIndex..<endIndex] 
     } 
} 
+0

@ thanks, lubi twój wariant) – katleta3000

1

Oto, co wymyśliłem ze szczytu mojej głowy. Założę się, że jest lepszy sposób na zrobienie tego, więc zachęcam cię do kontynuowania prób.

func splitedString(string: String, length: Int) -> [String] { 
    var groups = [String]() 
    var currentGroup = "" 
    for index in string.startIndex..<string.endIndex { 
     currentGroup.append(string[index]) 
     if currentGroup.characters.count == 3 { 
      groups.append(currentGroup) 
      currentGroup = "" 
     } 
    } 

    if currentGroup.characters.count > 0 { 
     groups.append(currentGroup) 
    } 

    return groups 
} 

Tu były moje testy

let firstString = "123456789" 
let groups = splitedString(firstString, length: 3) 
// Returned ["123", "456", "789"] 

let secondString = "1234567" 
let moreGroups = splitedString(secondString, length: 3) 
// Returned ["123", "456", "7"] 
+0

To obcina ostatnią porcję, a nie pierwszą, jak w przykładzie w pytaniu. –

+0

Dzięki, czy można użyć funkcji 'split()'? – katleta3000

+0

Próbowałem tego użyć, ale bez żadnego szczęścia. – aahrens

0

Zrobiłem coś takiego, nic nie może utworzyć lepiej wygląda, ale jego wynik odpowiada na pytanie:

func splitedString(string: String, lenght: Int) -> [String] { 
    var result = [String](), count = 0, line = "" 
    for c in string.characters.reverse() { 
     count++; line.append(c) 
     if count == lenght {count = 0; result.append(String(line.characters.reverse())); line = ""} 
    } 
    if !line.isEmpty {result.append(String(line.characters.reverse()))} 
    return result.reverse() 
} 
1

Oto wersja przy użyciu NSRegularExpressions

func splitedString(string: String, length: Int) -> [String] { 
    var groups = [String]() 
    let regexString = "(\\d{1,\(length)})" 
    do { 
     let regex = try NSRegularExpression(pattern: regexString, options: .CaseInsensitive) 
     let matches = regex.matchesInString(string, options: .ReportCompletion, range: NSMakeRange(0, string.characters.count)) 
     let nsstring = string as NSString 
     matches.forEach { 
      let group = nsstring.substringWithRange($0.range) as String 
      groups.append(group) 
     } 
    } catch let error as NSError { 
     print("Bad Regex Format = \(error)") 
    } 

    return groups 
} 
1

Oto kolejna wersja z Programowaniem funkcjonalnym.

extension String{ 
    func splitedString(length: Int) -> [String]{ 
     guard length > 0 else { return [] } 
     let range = 0..<((characters.count+length-1)/length) 
     let indices = range.map{ length*$0..<min(length*($0+1),characters.count) } 
     return indices 
       .map{ characters.reverse()[$0.startIndex..<$0.endIndex] } 
       .map(String.init) 
    } 
} 

"1234567890".splitedString(3) 
0

Nie ma chyba bardziej eleganckie rozwiązanie, ale to działa:

func splitedString(string: String, length: Int) -> [String] { 
    let string = Array(string.characters) 
    let firstGroupLength = string.count % length 
    var result: [String] = [] 
    var group = "" 

    if firstGroupLength > 0 { 
     for i in 0..<firstGroupLength { 
      group.append(string[i]) 
     } 
     result.append(String(group)) 
     group = "" 
    } 

    for i in firstGroupLength..<string.count { 
     group.append(string[i]) 
     if group.characters.count == length { 
      result.append(group) 
      group = "" 
     } 
    } 
    return result 
} 

splitedString("abcdefg", length: 2) // ["a", "bc", "de", "fg"] 
splitedString("1234567", length: 3) // ["1", "234", "567"] 
0

inne rozwiązanie wykorzystujące podciągi:

func splitStringByIntervals(str: String, interval: Int) -> [String] { 

    let st = String(str.characters.reverse()) 
    let length = st.characters.count 
    var groups = [String]() 

    for (var i = 0; i < length; i += interval) { 
     groups.append((st as NSString).substringWithRange(NSRange(location: i, length: min(interval, length - i)))) 
    } 

    return groups.map{ String($0.characters.reverse())}.reverse() 
} 

Wyjście dla:

for element in splitStringByIntervals("1234567", interval: 3) { 
    print(element) 
} 

jest:

1 
234 
567 
1

Swift 4

Myślę, że metoda rozszerzenia jest bardziej przydatna.

extension String{ 

    public func splitedBy(length: Int) -> [String] { 

     var result = [String]() 

     for i in stride(from: 0, to: self.characters.count, by: length) { 
      let endIndex = self.index(self.endIndex, offsetBy: -i) 
      let startIndex = self.index(endIndex, offsetBy: -length, limitedBy: self.startIndex) ?? self.startIndex 
      result.append(String(self[startIndex..<endIndex])) 
     } 

     return result.reversed() 

    } 

} 

przykładzie użytku:

Swift.debugPrint("123456789".splitedBy(length: 4)) 
// Returned ["1", "2345", "6789"]