123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- //
- // NSString+Ex.swift
- // TSLiveWallpaper
- //
- // Created by 100Years on 2024/12/20.
- //
- import CommonCrypto
- public extension String {
-
- var uiColor: UIColor {
- if isEmpty {
- return .clear
- }
- return UIColor.fromHex(self)
- }
-
- var localFilePath: String {
- var path = self
- if path.lowercased().hasPrefix("file://") {
- path.removeFirst("file://".count)
- }
- return path
- }
-
- func toCgRect() -> CGRect {
- NSCoder.cgRect(for: self)
- }
-
- func toCgPoint() -> CGPoint {
- NSCoder.cgPoint(for: self)
- }
- func toRgba() -> (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat)? {
- var r:CGFloat = 0;
- var g:CGFloat = 0;
- var b:CGFloat = 0;
- var a:CGFloat = 0;
- var prefix: Int = 0;
- let color: String = trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
- if (color.hasPrefix("#")) {
- prefix = 1
- }
- else if (color.hasPrefix("0X")) {
- prefix = 2
- }
- let length: Int = color.count - prefix
- // RGB RGBA RRGGBB RRGGBBAA
-
- func componentFrom(string: String, start: Int, length: Int) -> CGFloat {
- guard start >= 0, start + length <= string.count else {
- return 0
- }
-
- let begin = string.index(startIndex, offsetBy: start)
- let end = string.index(startIndex, offsetBy: start + length)
-
- let sub = string[begin..<end]
- var full = String(sub)
- if length == 1 {
- full += full
- }
-
- var hex: UInt64 = 0
- Scanner(string: full).scanHexInt64(&hex)
-
- let float = CGFloat(hex) / 255.0
- return float
- }
-
- switch length {
- case 3: // RGB
- r = componentFrom(string: color, start: prefix, length: 1)
- g = componentFrom(string: color, start: prefix + 1, length: 1)
- b = componentFrom(string: color, start: prefix + 2, length: 1)
- a = 1
- case 4: // RGBA
- r = componentFrom(string: color, start: prefix, length: 1)
- g = componentFrom(string: color, start: prefix + 1, length: 1)
- b = componentFrom(string: color, start: prefix + 2, length: 1)
- a = componentFrom(string: color, start: prefix + 3, length: 1)
- case 6: // RRGGBB
- r = componentFrom(string: color, start: prefix, length: 2)
- g = componentFrom(string: color, start: prefix + 2, length: 2)
- b = componentFrom(string: color, start: prefix + 4, length: 2)
- a = 1
- case 8: // RRGGBBAA
- r = componentFrom(string: color, start: prefix, length: 2)
- g = componentFrom(string: color, start: prefix + 2, length: 2)
- b = componentFrom(string: color, start: prefix + 4, length: 2)
- a = componentFrom(string: color, start: prefix + 6, length: 2)
- default:
- return nil
- }
-
- return (r, g, b, a)
- }
-
- func toColor() -> UIColor? {
- if let rgba = toRgba() {
- return UIColor(red: rgba.r, green: rgba.g, blue: rgba.b, alpha: rgba.a)
- }
-
- return nil
- }
- }
- public extension String {
- var localized:String {
- return NSLocalizedString(self, comment: self)
- // return self
- }
-
- }
- public extension String {
- var doubleValue: Double? {
- Double(self)
- }
-
- var localNumber: String {
- if let value = Int(self), let numberString = value.localNumber {
- return numberString
- }
- return self
- }
-
- var md5:String {
- let data = Data(self.utf8)
- var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
- data.withUnsafeBytes {
- _ = CC_MD5($0.baseAddress, CC_LONG(data.count), &digest)
- }
- return digest.map { String(format: "%02x", $0) }.joined()
- }
- }
- public extension String {
- // 移除逗号
- func deleteDotSymbol() -> String {
- // 超过1000的数字,格式化成文本后会带 ','(en)/'٬'(ar)
- return replacingOccurrences(of: ",", with: "").replacingOccurrences(of: "٬", with: "")
- }
-
- }
- public extension String {
- /// 根据字符串动态创建类实例
- /// - Parameters:
- /// - type: 要创建的类类型(泛型)
- /// - bundle: 模块的命名空间(默认为 `nil`,即当前模块)
- /// - Returns: 创建的实例或 `nil`
- func toInstance<T:NSObject>(of type: T.Type, bundle: String? = nil) -> T? {
- // 获取完整的类名
- let namespace = bundle ?? Bundle.main.infoDictionary?["CFBundleName"] as? String ?? ""
- let className = "\(namespace).\(self)"
-
- // 通过类名获取类型
- guard let targetClass = NSClassFromString(className) as? T.Type else {
- return nil
- }
-
- // 创建实例
- return targetClass.init()
-
- }
-
-
- func toClass(bundle: String? = nil) -> AnyClass? {
- // 获取完整的类名
- let namespace = bundle ?? Bundle.main.infoDictionary?["CFBundleName"] as? String ?? ""
- let className = "\(namespace).\(self)"
-
- // 通过类名获取类型
- guard let targetClass = NSClassFromString(className) else {
- return nil
- }
-
- // 创建实例
- return targetClass
- }
- }
- public extension String {
-
- func boundingRect(ofAttributes attributes: [NSAttributedString.Key: Any], size: CGSize) -> CGRect {
- let boundingBox = boundingRect(
- with: size,
- options: [.usesLineFragmentOrigin, .usesFontLeading],
- attributes: attributes,
- context: nil
- )
- return boundingBox
- }
-
- func size(ofAttributes attributes: [NSAttributedString.Key: Any], maxWidth: CGFloat, maxHeight: CGFloat) -> CGSize {
- boundingRect(ofAttributes: attributes, size: .init(width: maxWidth, height: maxHeight)).size
- }
-
- func size(ofFont font: UIFont, maxWidth: CGFloat, maxHeight: CGFloat) -> CGSize {
- let constraintRect = CGSize(width: maxWidth, height: maxHeight)
- let boundingBox = boundingRect(
- with: constraintRect,
- options: [.usesLineFragmentOrigin, .usesFontLeading],
- attributes: [.font: font],
- context: nil
- )
- return boundingBox.size
- }
-
- func width(ofSize size: CGFloat, maxHeight: CGFloat) -> CGFloat {
- width(
- ofFont: UIFont.systemFont(ofSize: size),
- maxHeight: maxHeight
- )
- }
-
- func width(ofFont font: UIFont, maxHeight: CGFloat) -> CGFloat {
- size(
- ofAttributes: [NSAttributedString.Key.font: font],
- maxWidth: CGFloat(MAXFLOAT),
- maxHeight: maxHeight
- ).width
- }
-
- func height(ofSize size: CGFloat, maxWidth: CGFloat) -> CGFloat {
- height(
- ofFont: UIFont.systemFont(ofSize: size),
- maxWidth: maxWidth
- )
- }
-
- func height(ofFont font: UIFont, maxWidth: CGFloat) -> CGFloat {
- size(
- ofAttributes: [NSAttributedString.Key.font: font],
- maxWidth: maxWidth,
- maxHeight: CGFloat(MAXFLOAT)
- ).height
- }
-
- subscript(_ indexs: ClosedRange<Int>) -> String {
- let beginIndex = index(startIndex, offsetBy: indexs.lowerBound)
- let endIndex = index(startIndex, offsetBy: indexs.upperBound)
- return String(self[beginIndex...endIndex])
- }
-
- subscript(_ indexs: Range<Int>) -> String {
- let beginIndex = index(startIndex, offsetBy: indexs.lowerBound)
- let endIndex = index(startIndex, offsetBy: indexs.upperBound)
- return String(self[beginIndex..<endIndex])
- }
-
- subscript(_ indexs: PartialRangeThrough<Int>) -> String {
- let endIndex = index(startIndex, offsetBy: indexs.upperBound)
- return String(self[startIndex...endIndex])
- }
-
- subscript(_ indexs: PartialRangeFrom<Int>) -> String {
- let beginIndex = index(startIndex, offsetBy: indexs.lowerBound)
- return String(self[beginIndex..<endIndex])
- }
-
- subscript(_ indexs: PartialRangeUpTo<Int>) -> String {
- let endIndex = index(startIndex, offsetBy: indexs.upperBound)
- return String(self[startIndex..<endIndex])
- }
-
- var assetFormat: String? {
- let lowercased = lowercased()
- if lowercased.hasSuffix("heic") {
- return "heic"
- }
- if lowercased.hasSuffix("jpg") || lowercased.hasSuffix("jpeg") {
- return "jpeg"
- }
- if lowercased.hasSuffix("png") {
- return "png"
- }
- if lowercased.hasSuffix("gif") {
- return "gif"
- }
- return nil
- }
- }
- public extension String {
-
- func colors(separator:String) -> [UIColor] {
- let array = self.components(separatedBy: separator)
- var colors = [UIColor]()
- for string in array {
- colors.append(string.uiColor)
- }
- return colors
- }
-
- func cgColors(separator:String) -> [CGColor] {
- let array = self.components(separatedBy: separator)
- var colors = [CGColor]()
- for string in array {
- colors.append(string.uiColor.cgColor)
- }
- return colors
- }
- }
- public extension String {
-
- func jsonDict() -> [String:Any]? {
- // 将字符串转换为 Data
- if let jsonData = self.data(using: .utf8) {
- do {
- // 将 Data 解析为 JSON 对象
- let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
- // 尝试将 JSON 对象转换为字典
- if let jsonDict = jsonObject as? [String: Any] {
- // dePrint("转换后的字典: \(jsonDict)")
- return jsonDict
-
- } else {
- // dePrint("无法将 JSON 对象转换为字典。")
- }
- } catch {
- // dePrint("JSON 解析错误: \(error)")
- }
- } else {
- // dePrint("无法将字符串转换为 Data。")
- }
-
- return nil
- }
-
-
-
-
- }
- public extension String {
- func removeTimestampFromEnd() -> String {
- let string = self
- // // 正则表达式:匹配末尾的10位或13位数字
- // let pattern = "\\d{10}$|\\d{13}$"
- // guard let regex = try? NSRegularExpression(pattern: pattern) else {
- // return string
- // }
- // let range = NSRange(location: 0, length: string.utf16.count)
- // return regex.stringByReplacingMatches(in: string, options: [], range: range, withTemplate: "")
-
- // 正则表达式:匹配(可选下划线)后跟10位或13位数字结尾
- let pattern = "_?\\d{10}$|_?\\d{13}$"
- guard let regex = try? NSRegularExpression(pattern: pattern) else {
- return string
- }
- let range = NSRange(location: 0, length: string.utf16.count)
- return regex.stringByReplacingMatches(in: string, options: [], range: range, withTemplate: "")
-
- }
- }
|