更改属性字符串的文本并保留 Swift 中的属性
Change text of an attributed string and retain attributes in Swift
对于数据库程序中的输出,我有一些文本,我插入了标记以指示粗体或斜体,以及一些替换图像的文本。例如:
"%Important% ^All employees to the breakroom^" 最终输出应为:
重要 全体员工到休息室
我编写了代码来查找周围带有“%”符号和“^”符号的文本,但我现在遇到的问题是文本输出如下:
%重要%^全体员工到休息室^
我想删除这些 % 和 ^,同时保留字符串的格式。
这是我一直用到它失效的代码:
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
}
这适用于 % 匹配(但仅适用于第一个字符)并立即导致 ^ 字符崩溃。
对于解决此问题的任何帮助或建议,我们将不胜感激。谢谢
这是一个可能的解决方案,本质上是对
how to catch multiple instances special indicated **characters** in an NSString and bold them in between?
从 Objective-C 到 Swift.
想法是在一个循环中添加属性 和 删除定界符。 shift
在删除第一个分隔符后,需要变量来调整匹配范围。
为简单起见,仅显示“^...^”处理。
func processText(inString string: String) -> NSAttributedString {
let pattern = "(\^)(.*?)(\^)"
let regex = NSRegularExpression(pattern: pattern, options: nil, error: nil)!
var shift = 0 // number of characters removed so far
let attributedText = NSMutableAttributedString(string: string)
regex.enumerateMatchesInString(string, options: nil, range: NSMakeRange(0, count(string.utf16))) {
(result, _, _) -> Void in
var r1 = result.rangeAtIndex(1) // Location of the leading delimiter
var r2 = result.rangeAtIndex(2) // Location of the string between the delimiters
var r3 = result.rangeAtIndex(3) // Location of the trailing delimiter
// Adjust locations according to the string modifications:
r1.location -= shift
r2.location -= shift
r3.location -= shift
// Set attribute for string between delimiters:
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 14.0)!, range: r2)
// Remove leading and trailing delimiters:
attributedText.mutableString.deleteCharactersInRange(r3)
attributedText.mutableString.deleteCharactersInRange(r1)
// Update offset:
shift += r1.length + r3.length
}
return attributedText.copy() as! NSAttributedString
}
请注意 enumerateMatchesInString()
需要一个 NSRange
,因此您必须计算
UTF-16 字符的数量而不是 Swift 个字符的数量。
示例:
let text = "aaa ^bbb^ eee"
let attrText = processText(inString: text)
println(attrText)
输出:
aaa {
}bbb{
NSFont = " font-family: \"Helvetica-Oblique\"; font-weight: normal; font-style: italic; font-size: 14.00pt";
} eee{
}
马丁,
我最终使用了非常相似的东西,但我决定更改正则表达式以包含 ^ 标记。在这样做的过程中,我能够使用 "replaceCharactersInRange" 方法剪辑包含的属性子字符串的第一个和最后一个字符。到目前为止,这对我的目的来说效果更好一些,因为它是从属性字符串开始工作的,所以它不会搞砸或删除它的任何属性。
我附上了正则表达式和处理斜体的代码部分以供任何人将来参考(再次感谢!):
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
}
这对我有用!
extension UILabel {
func updateAttributedText(_ text: String) {
if let attributedText = attributedText {
let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText)
mutableAttributedText.mutableString.setString(text)
self.attributedText = mutableAttributedText
}
}
}
对于数据库程序中的输出,我有一些文本,我插入了标记以指示粗体或斜体,以及一些替换图像的文本。例如:
"%Important% ^All employees to the breakroom^" 最终输出应为:
重要 全体员工到休息室
我编写了代码来查找周围带有“%”符号和“^”符号的文本,但我现在遇到的问题是文本输出如下:
%重要%^全体员工到休息室^
我想删除这些 % 和 ^,同时保留字符串的格式。
这是我一直用到它失效的代码:
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
}
这适用于 % 匹配(但仅适用于第一个字符)并立即导致 ^ 字符崩溃。
对于解决此问题的任何帮助或建议,我们将不胜感激。谢谢
这是一个可能的解决方案,本质上是对 how to catch multiple instances special indicated **characters** in an NSString and bold them in between? 从 Objective-C 到 Swift.
想法是在一个循环中添加属性 和 删除定界符。 shift
在删除第一个分隔符后,需要变量来调整匹配范围。
为简单起见,仅显示“^...^”处理。
func processText(inString string: String) -> NSAttributedString {
let pattern = "(\^)(.*?)(\^)"
let regex = NSRegularExpression(pattern: pattern, options: nil, error: nil)!
var shift = 0 // number of characters removed so far
let attributedText = NSMutableAttributedString(string: string)
regex.enumerateMatchesInString(string, options: nil, range: NSMakeRange(0, count(string.utf16))) {
(result, _, _) -> Void in
var r1 = result.rangeAtIndex(1) // Location of the leading delimiter
var r2 = result.rangeAtIndex(2) // Location of the string between the delimiters
var r3 = result.rangeAtIndex(3) // Location of the trailing delimiter
// Adjust locations according to the string modifications:
r1.location -= shift
r2.location -= shift
r3.location -= shift
// Set attribute for string between delimiters:
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 14.0)!, range: r2)
// Remove leading and trailing delimiters:
attributedText.mutableString.deleteCharactersInRange(r3)
attributedText.mutableString.deleteCharactersInRange(r1)
// Update offset:
shift += r1.length + r3.length
}
return attributedText.copy() as! NSAttributedString
}
请注意 enumerateMatchesInString()
需要一个 NSRange
,因此您必须计算
UTF-16 字符的数量而不是 Swift 个字符的数量。
示例:
let text = "aaa ^bbb^ eee"
let attrText = processText(inString: text)
println(attrText)
输出:
aaa { }bbb{ NSFont = " font-family: \"Helvetica-Oblique\"; font-weight: normal; font-style: italic; font-size: 14.00pt"; } eee{ }
马丁,
我最终使用了非常相似的东西,但我决定更改正则表达式以包含 ^ 标记。在这样做的过程中,我能够使用 "replaceCharactersInRange" 方法剪辑包含的属性子字符串的第一个和最后一个字符。到目前为止,这对我的目的来说效果更好一些,因为它是从属性字符串开始工作的,所以它不会搞砸或删除它的任何属性。
我附上了正则表达式和处理斜体的代码部分以供任何人将来参考(再次感谢!):
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
}
这对我有用!
extension UILabel {
func updateAttributedText(_ text: String) {
if let attributedText = attributedText {
let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText)
mutableAttributedText.mutableString.setString(text)
self.attributedText = mutableAttributedText
}
}
}