// // String+public extension.swift // SwiftBasics // // Created by 侯伟 on 17/1/11. // Copyright © 2017年 侯伟. All rights reserved. // import Foundation import SwiftyJSON import CommonCrypto import URLNavigator public extension String { var completePicUrl: String { if !self.hasPrefix("http") { if self.hasPrefix("//") { return "http:" + self } else { return "http://fec-img.gan-hai.com" + self } } else { return self } } var length: Int { return self.count } } public extension JSON { /// JSON to String var jsonString: String { return rawString(String.Encoding.utf8, options: JSONSerialization.WritingOptions()) ?? "" } } // MARK: URL encode/decode public extension String { /// URL编码 var urlEncoded: String { return self.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed) ?? self } var urlEncodingWithQueryAllowedCharacters: String { return self.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? self } /// URL解码 var urlDecoded: String { return self.removingPercentEncoding ?? self } } // MARK: md5 public extension String { var MD5String: String { let cStrl = cString(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue)); let buffer = UnsafeMutablePointer.allocate(capacity: 16); CC_MD5(cStrl, CC_LONG(strlen(cStrl!)), buffer); var md5String = ""; for idx in 0...15 { let obcStrl = String.init(format: "%02x", buffer[idx]); md5String.append(obcStrl); } free(buffer); return md5String; } } // MARK: Base64 public extension String { /// Base64编码 var base64Encoded: String { return data.base64EncodedString(options: []) } /// Base64解码 var base64Decoded: String { return Data(base64Encoded: self, options: [])?.string ?? "" } } public extension String { var md5: String { let data = self.data var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) CC_MD5((data as NSData).bytes, CC_LONG(data.count), &digest) let hexBytes = digest.map { String(format: "%02hhx", $0) } return hexBytes.joined(separator: "") } var sha1: String { let data = self.data var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH)) CC_SHA1((data as NSData).bytes, CC_LONG(data.count), &digest) let hexBytes = digest.map { String(format: "%02hhx", $0) } return hexBytes.joined(separator: "") } } // MARK: Get the size of the text public extension String { /// 计算制定字体大小的文字显示尺寸(系统默认字体) func size(fontSize: CGFloat, width: CGFloat = CGFloat.greatestFiniteMagnitude) -> CGSize { return size(font: UIFont.systemFont(ofSize: fontSize), width: width) } /// 计算制定字体的文字显示尺寸 func size(font: UIFont, width: CGFloat = CGFloat.greatestFiniteMagnitude) -> CGSize { let size = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .byWordWrapping let attributes = [ NSAttributedString.Key.font: font, NSAttributedString.Key.paragraphStyle: paragraphStyle.copy() ] return (self as NSString).boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: attributes, context: nil).size } /// 获取文字几行的高度 /// - Parameter count: 几行 /// - Returns: 高度 func lineHeight(_ count: Int = 1, font: UIFont, width: CGFloat = CGFloat.greatestFiniteMagnitude) -> CGFloat { size(font: font, width: width).height * CGFloat(count) } } // MARK: Substring public extension String { func substring(_ fromIndex: Int, _ toIndex: Int = Int.max) -> String? { let len = self.length var start: Int var end: Int if fromIndex < 0 { start = 0 end = len + fromIndex } else { start = fromIndex if toIndex < 0 { end = len + toIndex } else { end = min(toIndex, len) } } if start > end { return nil } return self[start..) -> String? { let len = self.length if range.lowerBound >= len || range.upperBound < 0 { return nil } let startIndex = self.index(self.startIndex, offsetBy: max(0, range.lowerBound)) let endIndex = self.index(self.startIndex, offsetBy: min(len, range.upperBound)) return String(self[startIndex.. Character? { if index < 0 || index >= self.length { return nil } return self[self.index(self.startIndex, offsetBy: index)] } } // MARK: Trim public extension String { /// 删除前后空白符(包含空格、Tab、回车、换行符) var trimmed: String { return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } // MARK: Localized String public extension String { var localizedString: String { return NSLocalizedString(self, comment: "") } } // MARK: - NSData public extension String { /// 返回UTF8字符集的NSData对象 var data: Data { return self.data(using: String.Encoding.utf8, allowLossyConversion: false)! } } public extension Data { /// 返回UTF8字符串 var string: String { return String(data: self, encoding: String.Encoding.utf8) ?? "" } } // MARK: - Int public extension String { var int: Int32 { return (self as NSString).intValue } var integer: Int { return (self as NSString).integerValue } } public extension Int { var string: String { return String(self) } } // MARK: - Float public extension String { var float: Float { return (self as NSString).floatValue } } public extension Float { var string: String { return String(self) } } // MARK: - Double public extension String { var double: Double { return (self as NSString).doubleValue } } public extension Double { var string: String { return String(self) } } // MARK: - Bool public extension String { var bool: Bool { return (self as NSString).boolValue } } public extension Bool { var string: String { return self ? "true" : "false" } } public extension String { // 对象方法 func getFileSize() -> UInt64 { var size: UInt64 = 0 let fileManager = FileManager.default var isDir: ObjCBool = false let isExists = fileManager.fileExists(atPath: self, isDirectory: &isDir) // 判断文件存在 if isExists { // 是否为文件夹 if isDir.boolValue { // 迭代器 存放文件夹下的所有文件名 let enumerator = fileManager.enumerator(atPath: self) for subPath in enumerator! { // 获得全路径 let fullPath = self.appending("/\(subPath)") do { let attr = try fileManager.attributesOfItem(atPath: fullPath) size += attr[FileAttributeKey.size] as! UInt64 } catch { print("error :\(error)") } } } else { // 单文件 do { let attr = try fileManager.attributesOfItem(atPath: self) size += attr[FileAttributeKey.size] as! UInt64 } catch { print("error :\(error)") } } } return size } } // MARK: - 文字颜色 public extension String { func changeTextColor(color: UIColor, font: UIFont, text: String) -> NSMutableAttributedString { let nsString = NSString(string: self) let attributeString = NSMutableAttributedString(string: self) let arrRange = rangeOfString(string: nsString, andInString: text) for range in arrRange { attributeString.addAttributes([NSAttributedString.Key.font: font], range: range) attributeString.addAttributes([NSAttributedString.Key.foregroundColor: color], range: range) } return attributeString } func changeTextColor(color: UIColor, font: UIFont, firstText: String, secondText: String) -> NSMutableAttributedString { let nsString = NSString(string: self) let attributeString = NSMutableAttributedString(string: self) let firstArrRange = rangeOfString(string: nsString, andInString: firstText) for range in firstArrRange { attributeString.addAttributes([NSAttributedString.Key.font: font], range: range) attributeString.addAttributes([NSAttributedString.Key.foregroundColor: color], range: range) } let secondArrRange = rangeOfString(string: nsString, andInString: secondText) for range in secondArrRange { attributeString.addAttributes([NSAttributedString.Key.font: font], range: range) attributeString.addAttributes([NSAttributedString.Key.foregroundColor: color], range: range) } return attributeString } /// 获取字符出现的位置信息(支持多次位置获取) /// - Parameter string: 原始文本 /// - Parameter inString: 需要查找的字符 private func rangeOfString(string:NSString, andInString inString:String) -> [NSRange] { var arrRange = [NSRange]() var _fullText = string var rang:NSRange = _fullText.range(of: inString) while rang.location != NSNotFound { var location:Int = 0 if arrRange.count > 0 { if arrRange.last!.location + arrRange.last!.length < string.length { location = arrRange.last!.location + arrRange.last!.length } } _fullText = NSString.init(string: _fullText.substring(from: rang.location + rang.length)) if arrRange.count > 0 { rang.location += location } arrRange.append(rang) rang = _fullText.range(of: inString) } return arrRange } } public extension String { /// 从URL字符串解析查询参数 var urlQueryParameters: [String: String] { guard let url = URL(string: self) else { return [:] } return url.queryParameters } /// 从String中截取出参数 var urlParameters: [String: AnyObject]? { // 判断是否有参数 let text = self as NSString let range = text.range(of: "?") var params = [String: AnyObject]() // 截取参数 let paramsString = text.substring(with: range) // 判断参数是单个参数还是多个参数 if paramsString.contains("&") { // 多个参数,分割参数 let urlComponents = paramsString.components(separatedBy: "&") // 遍历参数 for keyValuePair in urlComponents { // 生成Key/Value let pairComponents = keyValuePair.components(separatedBy: "=") let key = pairComponents.first?.removingPercentEncoding let value = pairComponents.last?.removingPercentEncoding // 判断参数是否是数组 if let key = key, let value = value { params[key] = value as AnyObject // 已存在的值,生成数组 // if let existValue = params[key] { // if var existValue = existValue as? [AnyObject] { // existValue.append(value) // } else { // params[key] = [existValue, value] // } // } else { // params[key] = value as AnyObject // } } } } else { // 单个参数 let pairComponents = paramsString.components(separatedBy: "=") // 判断是否有值 if pairComponents.count == 1 { return nil } let key = pairComponents.first?.removingPercentEncoding let value = pairComponents.last?.removingPercentEncoding if let key = key, let value = value { params[key] = value as AnyObject } } return params } } public extension String { func custemReplaceString(of targetStr:String, with replaceStr:String, replaceColor: UIColor) -> NSMutableAttributedString { let labelString = self.replacingOccurrences(of: targetStr, with: replaceStr) let nsString = labelString as NSString let range = nsString.range(of: replaceStr) let mutableStr = NSMutableAttributedString(string: labelString) mutableStr.setAttributes([NSAttributedString.Key.foregroundColor: replaceColor], range: range) return mutableStr } } public extension String { /// 手机号格式化去0 var phoneFromatter: String { if let phone = Int64(self) { return String(phone) } return self } } // MARK: - 转换为NSNumber public extension String { var number: NSNumber? { let boolNumbers = ["true": true, "false": false, "yes": true, "no": false] let nilNumbers = ["nil", "null", "(null)", ""] let lowerStr = self.lowercased() if let value = boolNumbers[lowerStr] { return NSNumber(value: value) } if nilNumbers.contains(lowerStr) { return nil } guard let cstring = self.cString(using: .utf8) else { return nil } if self.rangeOfCharacter(from: CharacterSet(charactersIn: ".")) != nil { let cnumber = atof(cstring) if cnumber.isNaN || cnumber.isInfinite { return nil } return NSNumber(value: cnumber) } else { return NSNumber(value: atoll(cstring)) } } } // MARK: - 正则 public extension String { /// 检测Email 邮箱格式是否有效 static func checkEmailAddressIsValid(address: String?) -> Bool { guard address != nil else { return false } let regular = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}" let regularEmail = NSPredicate(format: "SELF MATCHES %@", regular) return regularEmail.evaluate(with: address) } } // MARK: - 手机号中间用 **** 替换 extension String { /// 手机号中间隐藏 func phoneFormat() -> String { guard self.length > 6 else { return self } let preStr = self.substring(0, 3) let suffixStr = self.substring(self.length - 4, self.length) return (preStr ?? "") + "****" + (suffixStr ?? "") } } // MARK: - 生成二维码 extension String { func createQRCode(size: CGSize = CGSize(width: 200, height: 200)) -> UIImage? { // 1. 字符串转 Data guard let data = self.data(using: .utf8) else { return nil } // 2. 创建二维码滤镜 guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil } qrFilter.setDefaults() qrFilter.setValue(data, forKey: "inputMessage") // 容错率:L(7%)/M(15%)/Q(25%)/H(30%),越高容错越强 qrFilter.setValue("H", forKey: "inputCorrectionLevel") // 3. 获取 CIImage 并放大(原生默认很小,必须放大否则模糊) guard let ciImage = qrFilter.outputImage else { return nil } let scaleX = size.width / ciImage.extent.width let scaleY = size.height / ciImage.extent.height let transform = CGAffineTransform(scaleX: scaleX, y: scaleY) let scaledCI = ciImage.transformed(by: transform) // 4. 转 UIImage if let cgImage = CIContext(options: [.useSoftwareRenderer: false]).createCGImage(scaledCI, from: scaledCI.extent) { return UIImage(cgImage: cgImage) } return nil } }