-1

How can we split a string according to a specific range and put the sliced items in arrays like the example below:

let sentence = "Str1 {M} Str2 {/M} Str3 {M} Str4 {/M} {M} Str5 {/M} Str6 {M} Str7 {/M}"

Note: Str1 , Str2 ... are a strings

What I want: (1,2,3 and 4)

 1) OutputBetweenM = [Str2, Str4, Str5, Str7]
 2) OutputOutsideM = [Str1, Str3, Str6]
 3) OutputBetweenM_Edited = [Str2Edited, Str4Edited, Str5Edited, Str7Edited]
 4) Output3 = [Str1, Str2Edited, Str3, Str4Edited, Str5Edited, Str6, Str7Edited]

and finally rewrite the new sentence by adding the new items in Output3 together (easy to me) to get this:

let Final_sentence = "Str1 {M} Str2Edited {/M} Str3 {M} Str4Edited {/M} {M} Str5Edited {/M} Str6 {M} Str7Edited {/M}"

That is what I try to do:
1st code:

let from = NSRegularExpression.escapedPattern(for: "{M}") // escapedPattern
let to = NSRegularExpression.escapedPattern(for: "{/M}")
let regex = "(?<=\(from))(.*?)(?=\(to))"
let ranges = sentence.ranges(of: regex, options: .regularExpression)
let matches = ranges.map{ sentence[$0] }
print(matches) /* OutputBetweenM: [" Str2 ", " Str4 ", " Str5 ", " Str7 "]  ( Correct ) */

2nd Code:

let from = NSRegularExpression.escapedPattern(for: "{M}") // escapedPattern
let to = NSRegularExpression.escapedPattern(for: "{/M}")

let regexIncluding = from + ".*?" + to
let rangesIncluding = sentence.ranges(of: regexIncluding, options: .regularExpression)
var mutableSentence = sentence
print(mutableSentence)
for range in rangesIncluding.reversed() {
    mutableSentence.replaceSubrange(range, with: "\n")
}
let excludedOnes = mutableSentence.components(separatedBy: .newlines)
print(excludedOnes) /* OutputOutsideM: ["Str1 ", " Str3 ", " ", " Str6 ", ""]  ( InCorrect :/) 
 Correct one : ["Str1 ", " Str3 ", " Str6 "] */

Extension used: from a post in this page : Index of a substring in a string with Swift

func ranges(of string: String, options: CompareOptions = .literal) -> [Range<Index>] {
    var result: [Range<Index>] = []
    var start = startIndex
    while let range = range(of: string, options: options, range: start..<endIndex) {
        result.append(range)
        start = range.lowerBound < range.upperBound ? range.upperBound : index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex
    }
    return result
}

And after that , I don't know how I can put them like Output3 , thx to @leo-dabus for his help.
Thanks in advance!

Hassan Taleb
  • 2,350
  • 2
  • 19
  • 24
  • When you state that your `excludedOnes` is *incorrect*, because you do not wish to see the `" "` resulting from space between `Str4` and `Str5` are you indicating that there may be no space between a closing `{/M}` and a following `{M}`, or that you just think the code should not report it? The answer to this effects the solution, for example the only answer at the time of writing would fail if there is no space, but solves your problem if there is. So what you do mean by "incorrect"? – CRD Jan 01 '18 at 23:25

1 Answers1

1

The question it is not so clear but if I understood correctly that should be simple. You just need to zip together the excludedOnes and the edited ones, enumerate the zipped array and append each element of the tuple to the Output3. Once you have the Output3 array just filter where trimmingCharacters(in: .whitespaces) is not equal to an empty string and replace the ranges found with your edited array:

let excludedOnes = ["Str1 ", " Str3 ", " ", " Str6 ", ""]
let OutputBetweenM_Edited = ["Str2Edited", "Str4Edited", "Str5Edited", "Str7Edited"]

let zipped = zip(excludedOnes,OutputBetweenM_Edited)
print(zipped)
var output3: [String] = []
for item in zipped {
    output3.append(item.0)
    output3.append(item.1)
}
output3 = output3.filter{ $0.trimmingCharacters(in: .whitespaces) != "" }   
print("output3:",output3)

output3: ["Str1 ", "Str2Edited", " Str3 ", "Str4Edited", "Str5Edited", " Str6 ", "Str7Edited"]

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • thx bro , if the sentence like this: let sentence = "Str1 {M} Str2 {/M} Str3 {M} Str4 {/M} {M} Str5 {/M} Str6 {M} Str7 {/M} Final Str" , the Final Str doesn't appear in the output3 – Hassan Taleb Jan 05 '18 at 15:54
  • I solved it by this : `if excludedOnes.count > OutputBetweenM_Edited.count { OutputBetweenM_Edited.append("") } else { excludedOnes.append("") }` but it is not a nice solution – Hassan Taleb Jan 05 '18 at 16:17