// // String+Extension.swift // Lanu // // Created by OneeChan on 2025/11/6. // import Foundation import CommonCrypto extension String { init(key: String) { self = LNAppConfig.shared.languageBundle.localizedString(forKey: key, value: key, table: nil) } init(key: String, _ with: any CVarArg...) { let format = LNAppConfig.shared.languageBundle.localizedString(forKey: key, value: key, table: nil) self = String(format: format, with) } } extension String { /// 计算字符串的 MD5 哈希值(小写 32 位) var md5: String { // 将字符串转换为 UTF-8 数据 guard let data = self.data(using: .utf8) else { return "" } return data.md5 } } extension String { func toQRCode(size: CGFloat = 200, correctionLevel: String = "H") -> UIImage? { guard let contentData = data(using: .utf8) else { Log.e("字符串编码失败(仅支持 UTF-8)") return nil } // 2. 创建 CIQRCodeGenerator 滤镜 guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { Log.e("创建二维码滤镜失败") return nil } // 3. 设置滤镜参数:内容 + 容错率 qrFilter.setValue(contentData, forKey: "inputMessage") // 容错率可选值:L(7%)、M(15%)、Q(25%)、H(30%),H 容错率最高 qrFilter.setValue(correctionLevel, forKey: "inputCorrectionLevel") // 4. 获取 CIImage(原始二维码是小尺寸模糊图,需缩放) guard let ciImage = qrFilter.outputImage else { Log.e("生成 CIImage 失败") return nil } // 5. 缩放 CIImage 到指定尺寸(避免模糊) let scaleX = size / ciImage.extent.width let scaleY = size / ciImage.extent.height let scaledImage = ciImage.transformed(by: CGAffineTransform(scaleX: scaleX, y: scaleY)) // 6. 转为 UIImage 并返回 return UIImage(ciImage: scaledImage) } } extension String { // 修复 UUID 变化后的路径 var fixedFilePath: String? { let currentAppRootPath = URL.rootDir.path // 解析原始路径的「子目录+文件名」(剔除沙盒根前缀+旧UUID) let sandboxPrefix = "/var/mobile/Containers/Data/Application/" guard hasPrefix(sandboxPrefix) else { return nil } // 截取沙盒前缀后的部分(旧UUID/子目录/文件名) let pathAfterPrefix = dropFirst(sandboxPrefix.count) // 拆分出「旧UUID」和「后续路径」(以第一个"/"分割) guard let firstSlashIndex = pathAfterPrefix.firstIndex(of: "/") else { return nil } let relativePath = pathAfterPrefix[firstSlashIndex...] // 如 "/Documents/Caches/123.jpeg" // 拼接当前应用根目录 + 原子孙目录 let newPath = currentAppRootPath + relativePath return newPath } } // MARK: 拼音 extension String { var classificationFirstLetter: String { // 1. 空字符串直接返回"#" guard !trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return "#" } // 2. 统一预处理:转为可变字符串(支持CFStringTransform修改) let mutableString = NSMutableString(string: self) as CFMutableString // 3. 步骤1:中文转带声调拼音(对英/印尼语无影响,可安全执行) CFStringTransform(mutableString, nil, kCFStringTransformMandarinLatin, false) // 4. 步骤2:去除所有重音符号(关键:处理印尼语重音+中文拼音声调) CFStringTransform(mutableString, nil, kCFStringTransformStripDiacritics, false) // 5. 步骤3:提取处理后的字符串首字符(忽略空白字符) let processedString = mutableString as String guard let firstChar = processedString .trimmingCharacters(in: .whitespacesAndNewlines) .first else { return "#" } let firstLetter = String(firstChar).uppercased() // 6. 步骤4:判断是否为A-Z字母,统一返回结果 let isValidLetter = firstLetter.range(of: "^[A-Z]$", options: .regularExpression) != nil return isValidLetter ? firstLetter : "#" } var normalizedFullString: String { guard !isEmpty else { return "" } let mutableString = NSMutableString(string: self) as CFMutableString CFStringTransform(mutableString, nil, kCFStringTransformMandarinLatin, false) CFStringTransform(mutableString, nil, kCFStringTransformStripDiacritics, false) return (mutableString as String).uppercased() } } extension String { var extractSize: CGSize { let pattern = "(\\d+)x(\\d+)" guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return .zero } let range = NSRange(startIndex..., in: self) guard let match = regex.firstMatch(in: self, options: [], range: range) else { return .zero } let width = if let widthRange = Range(match.range(at: 1), in: self) { Int(String(self[widthRange])) } else { 0 } let height = if let heightRange = Range(match.range(at: 2), in: self) { Int(String(self[heightRange])) } else { 0 } return .init(width: width!, height: height!) } }