如何替换AttributedString中的字符以保留Markdown解析后的换行
解决Swift中用.full解析Markdown后换行丢失的问题
使用.full语法解析Markdown时,虽然能支持标题(.inlineOnly和.inlineOnlyPreservingWhitespace会忽略标题),但解析后所有换行都会被移除。尝试先将换行替换为虚拟Unicode字符♥,解析完成后再换回换行,但直接操作AttributedString的字符时出现崩溃或无法正确替换的问题。
方案一:借助NSMutableAttributedString处理替换
Swift的AttributedString是值类型,直接循环修改字符索引容易因索引失效导致崩溃。可以先将其转换为NSMutableAttributedString,利用Foundation的字符串替换API完成操作,再转换回AttributedString:
func getAttributedText(text: String) -> AttributedString { let textWithReplacements = text.replacingOccurrences(of: "\n", with: "\n♥") guard let attributedText = try? AttributedString( markdown: textWithReplacements, options: .init( allowsExtendedAttributes: true, interpretedSyntax: .full, failurePolicy: .returnPartiallyParsedIfPossible ), baseURL: nil ) else { return AttributedString(stringLiteral: text) } // 转换为可变NSAttributedString let nsMutableAttr = NSMutableAttributedString(attributedText) let fullRange = NSRange(location: 0, length: nsMutableAttr.length) // 批量替换所有♥为换行 nsMutableAttr.mutableString.replaceOccurrences(of: "♥", with: "\n", options: [], range: fullRange) // 转换回Swift AttributedString guard let result = try? AttributedString(nsMutableAttr, including: \.uiKit) else { return attributedText } return result }
方案二:纯Swift原生从后往前替换
如果不想依赖Foundation,可以从后往前遍历AttributedString的字符,这样修改时不会影响未处理的索引,避免崩溃:
func getAttributedText(text: String) -> AttributedString { let textWithReplacements = text.replacingOccurrences(of: "\n", with: "\n♥") guard var attributedText = try? AttributedString( markdown: textWithReplacements, options: .init( allowsExtendedAttributes: true, interpretedSyntax: .full, failurePolicy: .returnPartiallyParsedIfPossible ), baseURL: nil ) else { return AttributedString(stringLiteral: text) } // 从后往前遍历,防止索引失效 var currentIndex = attributedText.endIndex while currentIndex > attributedText.startIndex { currentIndex = attributedText.index(before: currentIndex) if attributedText[currentIndex] == "♥" { // 替换当前♥为换行 attributedText.replaceSubrange(currentIndex...currentIndex, with: "\n") } } return attributedText }
原代码崩溃原因
你之前的循环操作直接使用了原attributedText的字符索引,而AttributedString是值类型,修改output后,原索引已经和新字符串不匹配,继续使用会导致索引越界,引发崩溃。从后往前遍历或借助NSMutableAttributedString都能避免这个问题。
内容的提问来源于stack exchange,提问作者Programmer54
相关产品推荐
相关产品推荐

