For output in a database program, I have certain text that I've inserted marks to indicate bold or italics, as well as some text that is substituted for images. For instance:
"%Important% ^All employees to the breakroom^" should have final output as:
Important All employees to the breakroom
I have code written to find the text with "%" signs around it and "^" signs, but the trouble I have now is the text outputs like:
%Important% ^All employees to the breakroom^
I'd like to remove these % and ^'s while retaining the string's formatting.
This is the code I'm using up until it breaks:
func processText(inString string: String) -> NSAttributedString {
let pattern = ["(?<=\\^).*?(?=\\^)","(?<=\\%).*?(?=\\%)","\\^", "\\%"]
let italicsRegex = NSRegularExpression(pattern: pattern[0], options: .allZeros, error: nil)
let range = NSMakeRange(0, count(string))
let italicsMatches = italicsRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult]
var attributedText = NSMutableAttributedString(string: string)
for match in italicsMatches! {
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 14.0)!, range: match.range)
}
let boldRegex = NSRegularExpression(pattern: pattern[1], options: .allZeros, error: nil)
let boldMatches = boldRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult]
for match in boldMatches! {
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: match.range)
}
let removeItalicsMarksRegex = NSRegularExpression(pattern: pattern[2], options: .allZeros, error: nil)
let removeItalicsMarksMatches = removeItalicsMarksRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult]
var numberOfLoops = 0
for match in removeItalicsMarksMatches! {
attributedText.replaceCharactersInRange(match.range, withString: "")
}
return attributedText.copy() as! NSAttributedString
}
This works for the % match (but only the first character) and causes a crash on the ^ character immediately.
Any help or advice with resolving this would be appreciated. Thanks.
Martin,
I ended up using something very similar, but I decided to change the regular expression to include the ^ marks. In doing so, I was able to then clip the first and last characters of the included attributed substring with the "replaceCharactersInRange" method. This works a little better for my purposes so far because it's working from the attributed string so it doesn't screw up or remove any of its attributes.
I've attached the regex and the portion of the code that deals with italics for anyone's future reference (and thanks, again!):
func processText(inString string: String) -> NSAttributedString {
let pattern = ["\\^.*?\\^"] //Presented as an array here because in the full code there are a lot of patterns that are run.
let italicsRegex = NSRegularExpression(pattern: pattern[0], options: .allZeros, error: nil)
//In addition to building the match for this first regular expression, I also gather build the regular expressions and gather matches for all other matching patterns on the initial string ("string") before I start doing any processing.
let range = NSMakeRange(0, count(string.utf16))
let italicsMatches = italicsRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult]
var attributedText = NSMutableAttributedString(string: string)
var charactersRemovedFromString = 0
for match in italicsMatches! {
let newRange = NSMakeRange(match.range.location - charactersRemovedFromString, match.range.length) // Take the updated range for when this loop iterates, otherwise this crashes.
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 12.0)!, range: newRange)
let rangeOfFirstCharacter = NSMakeRange(match.range.location - charactersRemovedFromString, 1)
attributedText.replaceCharactersInRange(rangeOfFirstCharacter, withString: "")
charactersRemovedFromString += 2
let rangeOfLastCharacter = NSMakeRange(match.range.location + match.range.length - charactersRemovedFromString, 1)
attributedText.replaceCharactersInRange(rangeOfLastCharacter, withString: "")
}
return attributedText
}