Swift中的RegexBuilder怎么正确使用 |
您所在的位置:网站首页 › 买苹果13的订单 › Swift中的RegexBuilder怎么正确使用 |
Swift中的RegexBuilder怎么正确使用
发布时间:2023-04-07 17:35:40
来源:亿速云
阅读:81
作者:iii
栏目:开发技术
本篇内容主要讲解“Swift中的RegexBuilder怎么正确使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Swift中的RegexBuilder怎么正确使用”吧! 前言在我们日常的项目开发中,经常会碰到和正则表达式打交道的时候。比如用户密码,通常会要求同时包含小写字母、大写字母、数字,并且长度不少于 8 位,以此来提高密码的安全性。 在 Swift 中,我们可以用正则表达式的字面量方式来进行实现。 Regex 字面量Regex 字面量实现代码: let regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/ let text = "Aa11111111" print(text.matches(of: regex).first?.output) // Optional("Aa11111111")通过上述代码可以看到,//通过两个斜线就可以来生成正则的字面量。用字面量的方式确实可以使代码很简洁,但简洁的代价就是很难看懂,对后面的代码维护也造成了很大的困难。 就像网上盛传的一句梗一样:“我有一个问题,所以我写了一个正则表达式。现在,我有了两个问题。”???? 对于 Regex 难懂且难维护的问题,Swift 的开发团队给出的方案就是:RegexBuilder。 RegexBuilder - 像写代码一样写正则假设我们有一个字符串"name: John Appleseed, user_id: 100",想要提取其中user_id的值。 首先第一步,先导入 RegexBuilder: import RegexBuilder接着,通过结构体 Regex 来构建正则语句: let regex = Regex { "user_id:" // 1 OneOrMore(.whitespace) // 2 Capture(.localizedInteger(locale: Locale(identifier: "zh-CN"))) // 3 }第一行代码匹配的是固定字符串:"user_id",第二行代码匹配的是一个或者多个空格,第三行代码则是匹配的整型数字。 localizedInteger 会将匹配到的数字自动转为整型,比如下面的例子: let input = "user_id: 100.11" let regex = Regex { Capture(.localizedInteger(locale: Locale(identifier: "zh-CN"))) } if let match = input.firstMatch(of: regex) { print("Matched: \(match.0)") // Matched: 100.11 print("User ID: \(match.1)") // User ID: 100 }虽然匹配的是 100.11,但输出的仍然是 100。 最后,就可以通过 macth 的相关函数来进行数据提取了: if let match = input.firstMatch(of: regex) { print("Matched: \(match.0)") print("User ID: \(match.1)") }RegexRepetitionBehavior该结构体是用来定义匹配的重复行为的,它有三个值: edger:会尽可能多的去匹配输入的字符,必要的时候会回溯。默认为edger reluctant:会尽可能少的去匹配输入的字符,它会根据你的需求来一点点增大匹配区域,以完成匹配。 possessive:会尽可能多的去匹配输入的字符,不会回溯。 比如下面这个例子: let testSuiteTestInputs = [ "2022-06-06 09:41:00.001", "2022-06-06 09:41:00.001.", "2022-06-06 09:41:00.001."] let regex = Regex { Capture(OneOrMore(.any)) Optionally(".") } for line in testSuiteTestInputs { if let (dateTime) = line.wholeMatch(of: regex)?.output { print("Matched: \(dateTime)\"") } }因为这三条数据最后的.是不一定有的,所以我们的正则有一个 Optionally(".")。但匹配出来的 dateTime 还是会带 .。因为 edger 会匹配所有的字符包含最后的点在内,这样 Optionally(".") 根本不会起作用。 改成 Capture(OneOrMore(.any, .reluctant))则会修复这个问题。因为 reluctant 它是匹配尽可能少的输入,所以最后的Optionally(".")会执行。 在 Swift 5.7 中,Foundation 框架也对 RegexBuilder 进行适配。所以对于 Date、URL等类型,我们可以借助 Foundation 的强大功能来进行解析。 Foundation 的支持假如,我们在做一个金融相关的 APP,为了兼容一些老数据,需要将一些字符串类型的数据转为结构体。 这是我们的字符串数据: let statement = """ CREDIT 2022/03/03 张三 ¥2,000,000.00 DEBIT 03/03/2022 Tom $2,000,000.00 DEBIT这是我们需要转的结构体: struct Trade { let type: String let date: Date let name: String let count: Decimal }下面这个就是我们需要编写的 Regex: let regex = Regex { Capture { /CREDIT|DEBIT/ } OneOrMore(.whitespace) Capture { One(.date(.numeric, locale: Locale(identifier: "zh_CN"), timeZone: .gmt)) } OneOrMore(.whitespace) Capture { OneOrMore(.word) } OneOrMore(.whitespace) Capture { One(.localizedCurrency(code: "CNY", locale: Locale(identifier: "zh_CN"))) } }首先,我们需要匹配固定的字符串:CREDIT/DEBIT,接着是匹配一个或者多个空格。 接下来就是 Foundation 的重头戏了,对于日期类型的字符串,我们并不需要写一些匹配年月日规则的正则,只需要借助 Foundation 内嵌的功能即可。这样做不仅省去了我们自己编写的时间,更重要的是:官方写的要比我们自己写的更能保证代码的正确性。 需要注意的是,Apple 推荐我们显式的写出 locale 属性,而不是下面这种跟随系统写法 : ❌ One(.date(.numeric, locale: Locale.current, timeZone: TimeZone.current))因为这种写法会带来多种预期,并不能保证数据的确定性。 匹配完日期,接着就是对空格和用户名的匹配。最后,是对交易金额的匹配,金额也是 Foundation 提供的函数来进行的匹配。 测试代码: let result = statement.matches(of: regex) var trades = [Trade]() result.forEach { match in let (_, type, date, name, count) = match.output trades.append(Trade(type: String(type), date: date, name: String(name), count: count)) } print(trades) // [SwiftDemo.Trade(type: "CREDIT", date: 2022-03-03 00:00:00 +0000, name: "张三", count: 2000000), SwiftDemo.Trade(type: "DEBIT", date: 2022-03-05 00:00:00 +0000, name: "李三", count: 33.27)]通过打印可以得知,输出的结果并不符合预期,漏掉了 Tom 那条数据。漏掉的原因可以通过代码一眼得知:因为对日期和金额我们显式的指定了是中国的格式,显然03/03/2022 这种格式是不符合年月日的格式的。这也体现了显式指定格式的好处:方便排查问题。 我们只要将日期格式转为年月日格式,再将 $ 转为 ¥ 即可让正则正确匹配。 首先,我们需要根据 currency 来来返回正确的 Date 类型: func pickStrategy(_ currency: Substring) -> Date.ParseStrategy { switch currency { case "$": return .date(.numeric, locale: Locale(identifier: "en_US"), timeZone: .gmt) case "¥": return .date(.numeric, locale: Locale(identifier: "zh_CN"), timeZone: .gmt) default: fatalError("We found another one!") } }接着,编写正则表达式来获取相应的字符串字段: let regex1 = #/ (? \d{2} / \d{2} / \d{4}) (? \P{currencySymbol}+) (? \p{currencySymbol}) /#注:#//#格式为 Swift 中运行时正则表达式的格式。 最后,再调用 replace 函数来进行符合正则的字符替换: statement.replace(regex1) { match -> String in print(match.currency) let date = try! Date(String(match.date), strategy: pickStrategy(match.currency)) // ISO 8601, it's the only way to be sure let newDate = date.formatted(.iso8601.year().month().day()) return newDate + match.name + "¥" } statement = statement.replacingOccurrences(of: "-", with: "/")这样,我们就能解析出符合我们需求的 Trade 类型的数据了。 到此,相信大家对“Swift中的RegexBuilder怎么正确使用”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习! 推荐阅读: 深入理解Swift中的Substring和String 详解在Swift中使用KVO免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:[email protected]进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。 swift 上一篇新闻:Vue组合式API源码分析 下一篇新闻:Go语言中的Slice链式操作方法是什么 猜你喜欢 java数组如何实现ArrayList的动态扩容 C++中operator type函数的使用方法 C++命名空间的常见用法 elasticsearch整合SpringCloud的步骤 推箱子游戏用java怎么去写 如何设定Keras - GPU ID 和显存占用 jwt的优缺点和使用方法 Spring Boot开发环境热部署怎么配置 Spring boot AOP通过XML配置文件声明切面的方法 format函数在python中的应用 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |