Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 21 additions & 11 deletions Sources/Lingo/StringInterpolator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@ import Foundation

final class StringInterpolator {

private static let regularExpression = try! NSRegularExpression(pattern: "\\%\\{[^\\}]*\\}", options: []) // swiftlint:disable:this force_try
private static let regexPattern = "\\%\\{[^\\}]*\\}"

/// Input string is in format: "You have %{count} unread messages".
/// The function finds all placeholders and replaces them with a value specified in interpolations dictionary
func interpolate(_ rawString: String, with interpolations: [String: Any]) -> String {
var result = rawString
let matches = StringInterpolator.regularExpression.matches(in: rawString, options: [], range: NSRange.init(location: 0, length: rawString.count))

for match in matches {
let range: NSRange = match.range
let ranges: [Range<String.Index>] = findRanges(in: rawString, startingFrom: rawString.startIndex)

return ranges.reduce(into: rawString) { result, range in

// Extract whole capture group string. Will contain string like: "%{count}"
let startIndex = rawString.index(rawString.startIndex, offsetBy: range.location)
let endIndex = rawString.index(startIndex, offsetBy: range.length)
let matchedString = String(rawString[startIndex..<endIndex])
let matchedString = String(rawString[range.lowerBound..<range.upperBound])

// Extract the key from `matchedString`. Will contain string like: "count"
let keyStartIndex = matchedString.index(matchedString.startIndex, offsetBy: 2)
Expand All @@ -26,9 +23,22 @@ final class StringInterpolator {
if let interpolation = interpolations[key] {
result = result.replacingOccurrences(of: matchedString, with: "\(interpolation)")
}

}
}

func findRanges(in text: String, startingFrom start: String.Index) -> [Range<String.Index>] {
let end = text.endIndex
guard let range = text.range(of: Self.regexPattern, options: .regularExpression,
range: start..<end) else {
return ([])
}

return result
let cursor = range.upperBound

let recursiveResult = self.findRanges(in: text, startingFrom: cursor)

return ([range] + recursiveResult)

}

}