Swift中按特定范围分割字符串并生成指定数组及重构语句
Hey there! Let's work through this step by step to get all your desired outputs sorted out, including fixing the OutputOutsideM issue and generating Output3 and the final reconstructed sentence.
First, Let's Define Our Base Variables
We'll start with your original sentence and reusable markers to keep code clean:
let sentence = "Str1 {M} Str2 {/M} Str3 {M} Str4 {/M} {M} Str5 {/M} Str6 {M} Str7 {/M}" let startMarker = "{M}" let endMarker = "{/M}" let escapedStart = NSRegularExpression.escapedPattern(for: startMarker) let escapedEnd = NSRegularExpression.escapedPattern(for: endMarker)
1. Get OutputBetweenM (Your Working Code, Optimized)
Your original code already works, but we can trim whitespace to match your expected output exactly:
let betweenRegex = "(?<=\(escapedStart))(.*?)(?=\(escapedEnd))" let betweenRanges = sentence.ranges(of: betweenRegex, options: .regularExpression) let outputBetweenM = betweenRanges.map { sentence[$0].trimmingCharacters(in: .whitespaces) } print(outputBetweenM) // ["Str2", "Str4", "Str5", "Str7"] ✅
2. Fix OutputOutsideM
The issue with your original code was leftover empty/whitespace-only strings from consecutive {M} blocks. We'll filter those out:
let blockRegex = escapedStart + ".*?" + escapedEnd let blockRanges = sentence.ranges(of: blockRegex, options: .regularExpression) var tempSentence = sentence // Replace all {M}...{/M} blocks with newlines for range in blockRanges.reversed() { tempSentence.replaceSubrange(range, with: "\n") } // Split and filter out empty/whitespace-only entries let outputOutsideM = tempSentence.components(separatedBy: .newlines) .filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty } .map { $0.trimmingCharacters(in: .whitespaces) } // Optional: trim extra spaces if needed print(outputOutsideM) // ["Str1", "Str3", "Str6"] ✅
3. Generate OutputBetweenM_Edited
This is straightforward—just apply your editing logic to each entry in outputBetweenM (we'll use appending "Edited" as your example shows):
let outputBetweenM_Edited = outputBetweenM.map { "\($0)Edited" } print(outputBetweenM_Edited) // ["Str2Edited", "Str4Edited", "Str5Edited", "Str7Edited"] ✅
4. Generate Output3 and Final_sentence
To build these, we'll split the original sentence into alternating "outside" content and {M}...{/M} blocks, then replace the blocks with their edited versions while preserving order:
// Regex to split the sentence into either {M}...{/M} blocks or outside content let splitRegex = "(\(blockRegex))|(.*?)(?=\(escapedStart)|$)" let splitRanges = sentence.ranges(of: splitRegex, options: .regularExpression) var output3: [String] = [] var finalSentenceParts: [String] = [] var betweenIndex = 0 // Track which edited between content to use for range in splitRanges { let part = sentence[range] if part.hasPrefix(startMarker) && part.hasSuffix(endMarker) { // Handle {M}...{/M} blocks: use edited content let editedContent = outputBetweenM_Edited[betweenIndex] output3.append(editedContent) finalSentenceParts.append("\(startMarker) \(editedContent) \(endMarker)") betweenIndex += 1 } else { // Handle outside content: add only if it's not empty let trimmedPart = part.trimmingCharacters(in: .whitespaces) if !trimmedPart.isEmpty { output3.append(trimmedPart) finalSentenceParts.append(part) } } } let finalSentence = finalSentenceParts.joined() print(output3) // ["Str1", "Str2Edited", "Str3", "Str4Edited", "Str5Edited", "Str6", "Str7Edited"] ✅ print(finalSentence) // "Str1 {M} Str2Edited {/M} Str3 {M} Str4Edited {/M} {M} Str5Edited {/M} Str6 {M} Str7Edited {/M}" ✅
Don't Forget Your ranges(of:) Extension
Keep this handy extension you're using for regex range matching:
extension String { 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 } }
内容的提问来源于stack exchange,提问作者Hassan Taleb

