Skip to content

Instantly share code, notes, and snippets.

@warrenburton
Last active May 31, 2016 19:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save warrenburton/6e20b55a4d6d01329b25ae82092e00a7 to your computer and use it in GitHub Desktop.
Save warrenburton/6e20b55a4d6d01329b25ae82092e00a7 to your computer and use it in GitHub Desktop.
String substitution utility - pass a dictionary of substitution values to a tagged string to globally replace. Supports basic looping
extension NSRange {
func toStringRange( string:String ) -> Range<String.Index>? {
guard location != NSNotFound else { return nil }
return string.startIndex.advancedBy(location)..<string.startIndex.advancedBy(location + length)
}
}
extension String {
/**
Replace <forin:outerkey>${innerkey}<forin> with corresponding dictionary values.
e.g "<forin:firstname>${name}<forin> Smith\n" with ["firstname":[["name":"John"],["name":"Mary"]]]
yields
John Smith
Mary Smith
- parameter markers: dictionary of key -> substitution value
- returns: String with looping tags removed and any substitutions made
*/
func stringByReplacingLoopedSubstitutionMarkers(markers:Dictionary<String,AnyObject>) -> String {
let regex = try! NSRegularExpression(pattern:"<forin:[^>]+>[^<]+<forin>", options:[])
let innerregex = try! NSRegularExpression(pattern:"<forin:[^>]+>", options:[])
var output = self
var result:NSTextCheckingResult?
var newloc = 0
repeat {
let newLength = output.characters.count - newloc
if newLength > 0 {
let newrange = NSRange(location:newloc,length:newLength)
result = regex.firstMatchInString(output, options:[], range:newrange)
}
else {
result = nil
}
if let xresult = result,swrange = xresult.range.toStringRange(output) {
let substring = output.substringWithRange(swrange)
newloc = xresult.range.location + xresult.range.length
let trimEnd = substring.substringToIndex(substring.endIndex.advancedBy(-7))
if let innerResult = innerregex.firstMatchInString(trimEnd, options: [], range: NSRange(location:0,length:trimEnd.characters.count)) {
let index = trimEnd.startIndex.advancedBy(innerResult.range.length)
let innermarker = trimEnd.substringWithRange(Range(trimEnd.startIndex.advancedBy(7)..<index.advancedBy(-1)))
let template = String(trimEnd.substringFromIndex(index))
var finalSubstring = ""
print("innermarker = \(innermarker)")
if let submarker = markers[innermarker] as? [Dictionary<String,String>] {
print("submarker = \(submarker)")
for dict in submarker {
let innerSub = template.stringByReplacingSubstitutionMarkers(dict)
finalSubstring += innerSub
}
}
output = output.stringByReplacingCharactersInRange(swrange, withString: finalSubstring)
}
}
}
while(result != nil)
return output
}
/**
Replace substitution marker with value in string.
e.g "Hello ${name} your ${clothing} is ${adjective}" with ["name":"Bob","clothing":"shirt","adjective":"nice"]
yields
"Hello Bob your shirt is nice"
- parameter markers: dictionary of key -> substitution value
- returns: sustituted composed string, unfound markers are left in the string.
*/
func stringByReplacingSubstitutionMarkers(markers:Dictionary<String,AnyObject>)->String {
let regex = try! NSRegularExpression(pattern:"\\$\\{[^}]+\\}", options:[])
let charset = NSCharacterSet(charactersInString: "${}")
var output = self.stringByReplacingLoopedSubstitutionMarkers(markers)
var result:NSTextCheckingResult?
var newloc = 0
repeat {
let newlength = output.characters.count - newloc
if newlength > 0 {
let newrange = NSRange(location:newloc,length:newlength)
result = regex.firstMatchInString(output, options:[], range:newrange)
}
else {
result = nil
}
if let xresult = result,swrange = xresult.range.toStringRange(output) {
let substring = output.substringWithRange(swrange)
let marker = substring.stringByTrimmingCharactersInSet(charset)
if let submarker = markers[marker] as? String {
output = regex.stringByReplacingMatchesInString(output, options: [], range: xresult.range, withTemplate:submarker)
newloc = xresult.range.location + submarker.characters.count
} else {
newloc = xresult.range.location + xresult.range.length
}
}
}
while(result != nil)
return output
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment