Swift中JSON文本加粗显示字符缺失问题的修复指导
Swift解析JSON时自定义处理*加粗文本字符缺失问题修复
在Swift开发中,解析后端返回的JSON文本时,使用自定义代码处理带*标记的加粗文本出现字符缺失问题,例如"School Timings"的l和T、"08:25 am"的a等字符丢失。以下是相关信息及修复方案:
后端返回的JSON文本
"Body" : "16.03.2024\r\n\r\nDear Parents (KG)\r\n\r\nKindly adhere to the summer timings from *Monday (18\/03\/2024) to Friday(29\/03\/2024)\r\n\r\n **School Timings:* \r\n **Monday - Friday* \r\n *08:25 am - 11:30 am*** \r\n\r\n *Note:* Students should be present in the school campus before *8:25 am* .\r\n\r\n* From *01\/04\/2024(Monday),* the school school timings will be *08:25 am to 01:00 pm.* \r\n\r\n* Students will adhere to summer uniform from *April 1, 2024 (Monday).* \r\n\r\nRegards\r\n\r\nSr Anandi Pinto\r\nPrincipal"
当前实现代码
lblMessage?.attributedText = checkingTheBoldItalicAndStrickLineForBoadyMessage(objText: modal.body) func checkingTheBoldItalicAndStrickLineForBoadyMessage(objText: String) -> NSMutableAttributedString { var objFinalString = String() let fullNameArr = objText.components(separatedBy: " ") let finalString = NSMutableAttributedString() var objGetString = objText if objGetString.first == " " && objGetString.last == "_" && objGetString.count > 2 { objGetString.removeFirst() objGetString.removeLast() objGetString.append(" ") let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont(name: "Ubuntu-Bold", size: 16)! ] finalString.append(NSAttributedString(string: objGetString, attributes: attributes)) objFinalString.append(objGetString) } else if objGetString.first == "/" && objGetString.last == "/" && objGetString.count > 2 { objGetString.removeFirst() objGetString.removeLast() objGetString.append(" ") let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont(name: "Ubuntu-Italic", size: 14)! ] finalString.append(NSAttributedString(string: objGetString, attributes: attributes)) objFinalString.append(objGetString) } else { for objStr in fullNameArr { var objString = objStr if (objString.first == "*" || objString.last == "*") && objString.count > 2 { objString.removeFirst() objString.removeLast() objString.append(" ") let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont(name: "Ubuntu-Bold", size: 16)! ] finalString.append(NSAttributedString(string: objString, attributes: attributes)) objFinalString.append(objString) finalString.mutableString.replaceOccurrences(of: "*", with: "*", options: NSString.CompareOptions.caseInsensitive, range: NSRange(location: 0, length: finalString.length)) objFinalString.replacingOccurrences(of: "*", with: "*") } else if (objString.first == "_" || objString.last == "_") && objString.count > 2 { objString.removeFirst() objString.removeLast() objString.append(" ") let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont(name: "Ubuntu-Italic", size: 14)! ] finalString.append(NSAttributedString(string: objString, attributes: attributes)) objFinalString.append(objString) finalString.mutableString.replaceOccurrences(of: "_", with: "", options: NSString.CompareOptions.caseInsensitive, range: NSRange(location: 0, length: finalString.length)) objFinalString.replacingOccurrences(of: "_", with: "") } else { objString.append(" ") finalString.append(NSMutableAttributedString(string: objString)) objFinalString.append(objString) } } } return finalString }
问题表现
处理后的文本中加粗部分出现字符缺失,例如:
- "School Timings"变成"Schoo imings"(丢失了
l和T) - "08:25 am"变成"08:25 m"(丢失了
a)
问题原因
- 按空格分割字符串的逻辑错误:后端的加粗内容可能跨多个空格(如
**School Timings:*),按空格拆分后会把完整的加粗内容拆成多个独立片段,导致无法正确识别加粗范围。 - 粗暴的首尾字符移除:代码中只要字符串首尾任一位置是
*,就直接执行removeFirst()和removeLast(),会误删非*的正常字符。例如字符串**School,removeFirst()去掉一个*后变成*School,再removeLast()会删掉School的最后一个字符l,造成字符丢失。 - 未处理不规范的
*标记:后端返回的*存在不闭合、多*的情况,当前代码无法适配这类场景。
修复方案
改用正则表达式匹配所有被*包裹的内容,不管*的数量和位置,正确识别加粗范围并应用样式,同时保留正常字符。
修复后的代码
func convertMarkdownToAttributedText(_ text: String) -> NSMutableAttributedString { let baseFont = UIFont(name: "Ubuntu-Regular", size: 16)! let boldFont = UIFont(name: "Ubuntu-Bold", size: 16)! let italicFont = UIFont(name: "Ubuntu-Italic", size: 14)! // 先初始化基础富文本,应用默认字体 let attributedText = NSMutableAttributedString(string: text, attributes: [.font: baseFont]) // 匹配所有*包裹的内容(支持多个*开头/结尾) let boldPattern = "\\*+([^*]+)\\*+" guard let boldRegex = try? NSRegularExpression(pattern: boldPattern, options: []) else { return attributedText } // 查找所有匹配项,从后往前替换避免范围偏移 let matches = boldRegex.matches(in: text, options: [], range: NSRange(text.startIndex..., in: text)) for match in matches.reversed() { // 获取匹配的整个范围(包括*)和内容范围(去掉*) let fullRange = match.range let contentRange = match.range(at: 1) guard let contentString = (text as NSString).substring(with: contentRange).trimmingCharacters(in: .whitespacesAndNewlines) as String? else { continue } // 替换原内容为加粗样式的文本 let boldAttrString = NSAttributedString(string: contentString, attributes: [.font: boldFont]) attributedText.replaceCharacters(in: fullRange, with: boldAttrString) } // 处理_包裹的斜体内容(逻辑类似) let italicPattern = "_+([^_]+)_+" guard let italicRegex = try? NSRegularExpression(pattern: italicPattern, options: []) else { return attributedText } let italicMatches = italicRegex.matches(in: attributedText.string, options: [], range: NSRange(attributedText.string.startIndex..., in: attributedText.string)) for match in italicMatches.reversed() { let fullRange = match.range let contentRange = match.range(at: 1) guard let contentString = (attributedText.string as NSString).substring(with: contentRange).trimmingCharacters(in: .whitespacesAndNewlines) as String? else { continue } let italicAttrString = NSAttributedString(string: contentString, attributes: [.font: italicFont]) attributedText.replaceCharacters(in: fullRange, with: italicAttrString) } // 处理换行符,保证换行正常显示 attributedText.mutableString.replaceOccurrences(of: "\r\n", with: "\n", options: [], range: NSRange(location: 0, length: attributedText.length)) return attributedText } // 使用方式 lblMessage?.attributedText = convertMarkdownToAttributedText(modal.body)
代码说明
- 正则匹配:用
\*+([^*]+)\*+匹配一个或多个*包裹的内容,确保能兼容后端不规范的*标记。 - 从后往前替换:避免替换前面的内容导致后续匹配范围偏移。
- 保留正常字符:只移除包裹内容的
*,不会误删文本字符。 - 统一处理换行:将
\r\n替换为\n,保证文本换行显示正常。 - 分离逻辑:将加粗和斜体处理分开,代码更清晰易维护。
内容的提问来源于stack exchange,提问作者Swift
相关产品推荐
相关产品推荐

