You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

问题原因

  1. 按空格分割字符串的逻辑错误:后端的加粗内容可能跨多个空格(如**School Timings:*),按空格拆分后会把完整的加粗内容拆成多个独立片段,导致无法正确识别加粗范围。
  2. 粗暴的首尾字符移除:代码中只要字符串首尾任一位置是*,就直接执行removeFirst()和removeLast(),会误删非*的正常字符。例如字符串**School,removeFirst()去掉一个*后变成*School,再removeLast()会删掉School的最后一个字符l,造成字符丢失。
  3. 未处理不规范的*标记:后端返回的*存在不闭合、多*的情况,当前代码无法适配这类场景。

修复方案

改用正则表达式匹配所有被*包裹的内容,不管*的数量和位置,正确识别加粗范围并应用样式,同时保留正常字符。

修复后的代码

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)

代码说明

  1. 正则匹配:用\*+([^*]+)\*+匹配一个或多个*包裹的内容,确保能兼容后端不规范的*标记。
  2. 从后往前替换:避免替换前面的内容导致后续匹配范围偏移。
  3. 保留正常字符:只移除包裹内容的*,不会误删文本字符。
  4. 统一处理换行:将\r\n替换为\n,保证文本换行显示正常。
  5. 分离逻辑:将加粗和斜体处理分开,代码更清晰易维护。

内容的提问来源于stack exchange,提问作者Swift

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 04:20:22