1

I'm looking for a way to split a whole text into 2 or more parts. So if I have the following Code:

var Text = "INGREDIENTS\n Milk \nSugar \nSoda \nINFORMATIONS \nYou need to add more sugar"

var SplitPart1 = ""
var SplitPart2 = ""

How do I get the part from "INGREDIENTS" to "INFORMATIONS" in "SplitPart1" and "SplitPart2"? At the end, I need these two Strings:

SplitPart1: INGREDIENTS\n Milk \nSugar \nSoda \n

SplitPart2: INFORMATIONS \nYou need to add more sugar

jscs
  • 63,694
  • 13
  • 151
  • 195
Jamie
  • 11
  • 3
  • 1
    Possible duplicate of [Index of a substring in a string with Swift](https://stackoverflow.com/questions/32305891/index-of-a-substring-in-a-string-with-swift) – MadProgrammer Jan 12 '19 at 22:23

3 Answers3

2

I did a quick bit of searching and found Index of a substring in a string with Swift, however, the immediate answer to use isn't quite obvious, so I wrote this quick test...

let text = "INGREDIENTS\n Milk \nSugar \nSoda \nINFORMATIONS \nYou need to add more sugar"
if let range = text.range(of: "INFORMATIONS") {

    let start = text[..<range.lowerBound]
    let end = text[range.lowerBound...]

    print("start:", start)
    print("end:", end)
}

This is will produce...

//    start: INGREDIENTS
//    Milk
//    Sugar
//    Soda
//
//    end: INFORMATIONS
//    You need to add more sugar
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0

Here is a general way to split and join the string:

    extension String{
   func split(_ separatingString: String) -> [String]{
    return   components(separatedBy: separatingString).reduce(into: [], { (result, next) in
        result.isEmpty  ?  result.append(next)  : result.append(separatingString + next)
    })}}

 var Text = "INGREDIENTS\n Milk \nSugar \nSoda \nINFORMATIONS \nYou need to add more sugar"

 print(Text.split("INFORMATIONS"))

For an extension with more keywords.

Extension could be like this:

 extension String{
func split(_ separatingString: String) -> [String]{
        let array =  components(separatedBy: separatingString)
    return  array.first!.isEmpty  ?  array.dropFirst().map{separatingString + $0} :
        [array.first!] + array.dropFirst().map{separatingString + $0}
}

func splitArray(_ array :[String]) -> [String]{
    return   array.reduce( [self]) { (result, next) -> [String] in
        return  [String](result.compactMap{$0.split(next)}.joined())
     }
}
}






var Text = "INGREDIENTS\n Milk \nSugar \nSoda \nINFORMATIONS \nYou need to add more sugar"


print(Text.splitArray(["INFORMATIONS", "add", "Milk", "INGREDIENTS", "suger"]))

//["INGREDIENTS\n ", "Milk \nSugar \nSoda \n", "INFORMATIONS \nYou need to ", "add more sugar"]


  print(Text.splitArray(["INFORMATIONS", "INGREDIENTS"]))
  print(Text.splitArray(["INGREDIENTS", "INFORMATIONS"]))

 // ["INGREDIENTS\n Milk \nSugar \nSoda \n", "INFORMATIONS \nYou need to add more sugar"]
 // ["INGREDIENTS\n Milk \nSugar \nSoda \n", "INFORMATIONS \nYou need to add more sugar"]

This is not the fastest way but with a clear logic. keywords don't need to be ordered here. If you know the order , this method is slower than sequence tail recursive.

E.Coms
  • 11,065
  • 2
  • 23
  • 35
  • What's with the uuhhhh creative indentation? – Alexander Jan 13 '19 at 01:41
  • Also, you can just use `joined(separator:)`, rather than implementing it yourself with reduce. It's way clearer. – Alexander Jan 13 '19 at 01:42
  • And you shouldn't check `if result.count == 0` check if it is empty `result.isEmpty` – Leo Dabus Jan 13 '19 at 02:11
  • @Alexander, the result is an array not one string. – E.Coms Jan 13 '19 at 02:28
  • @LeoDabus, yes but this won't hurt. – E.Coms Jan 13 '19 at 02:28
  • 1
    To check whether a collection is empty, use its isEmpty property instead of comparing count to zero. Unless the collection guarantees random-access performance, calculating count can be an O(n) operation. https://developer.apple.com/documentation/swift/array/2949997-count – Leo Dabus Jan 13 '19 at 02:33
0

Provided you get the string in this format only and you can not change it. Below is some try to make it dynamic. You will get splited arrays, that can be used to populate data.

var Text = "INGREDIENTS\n Milk \nSugar \nSoda \nINFORMATIONS \nYou need to add more sugar \nSOMETHINGELSE \n Deliver soon"

//1) Define the Seperator Keys
let SeperatorKey: Set = ["INGREDIENTS", "INFORMATIONS", "SOMETHINGELSE"]

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        splitString(text: Text)
    }

    //2.This method will split the strings based on SeperatorKey
    func splitString(text: String){
        let textArray = text.split(separator: "\n")

        let (count, indexes) = getNumberAndIndexOfCategories(textArray: textArray)

        for i in 0..<count {
            let startIndex = indexes[i]
            let endIndex = i == (count - 1) ? textArray.count : indexes[i+1]
            let subTextArray = textArray[startIndex..<endIndex]

            print("SubText = \(subTextArray)")
        }
    }

    func getNumberAndIndexOfCategories(textArray: [String.SubSequence]) -> (Int, [Int]){
        var count = 0
        var indexes: [Int] = []
        for (index, string) in textArray.enumerated() {
            let trimmedString = string.trimmingCharacters(in: .whitespaces)
            if SeperatorKey.contains(String(trimmedString)){
                count = count + 1
                indexes.append(index)
            }
        }
        return (count, indexes)
    }
}
Abhisheks
  • 104
  • 1
  • 5