如何从完整字符串 iOS swift 中找到字符串的多个 NSRange

2023-12-24

let fullString = "Hello world, there are \(string(07)) continents and \(string(195)) countries."
let range = [NSMakeRange(24,2), NSMakeRange(40,3)]

需要找到整个完整字符串中数字的 NSRange,并且两个数字有可能相同。目前如上所示进行硬编码,消息可以是动态的,而硬编码值将出现问题。

我已经分割了字符串并尝试获取NSRange因为存在相同值的可能性。比如 stringOne 和 stringTwo。

func findNSMakeRange(initialString:String, fromString: String) {
        let fullStringRange = fromString.startIndex..<fromString.endIndex
        fromString.enumerateSubstrings(in: fullStringRange, options: NSString.EnumerationOptions.byWords) { (substring, substringRange, enclosingRange, stop) -> () in
            let start = distance(fromString.startIndex, substringRange.startIndex)
            let length = distance(substringRange.startIndex, substringRange.endIndex)
            let range = NSMakeRange(start, length)

            if (substring == initialString) {
                print(substring, range)
            }
        })
    }

收到类似错误Cannot invoke distance with an argument list of type (String.Index, String.Index)

大家有更好的解决办法吗?


你说你想迭代NSRange匹配字符串,以便您可以将粗体属性应用于相关子字符串。

在 Swift 5.7 及更高版本中,您可以使用新的Regex https://developer.apple.com/documentation/swift/regex:

string.ranges(of: /\d+/)
    .map { NSRange($0, in: string) }
    .forEach {
        attributedString.setAttributes(attributes, range: $0)
    }

或者,如果您发现传统的正则表达式太神秘,您可以导入RegexBuilder https://developer.apple.com/documentation/regexbuilder,并且您可以使用新的正则表达式 DSL:

string.ranges(of: Regex { OneOrMore(.digit) })
    .map { NSRange($0, in: string) }
    .forEach {
        attributedString.setAttributes(attributes, range: $0)
    }

现在,这种映射模式Range<String.Index> to a NSRange仅当您确实需要时才需要NSRange,现在很少需要。例如,如果您只想打印子范围,您可以这样做:

string.ranges(of: /\d+/)
    .forEach { print(string[$0]) }

或者,如果您需要更新可变的AttributedString在寻找原始范围的基础上String,你可以映射到Range<AttributedString.Index>:

string.ranges(of: /\d+/)
    .compactMap { Range($0, in: attributedString) }
    .forEach { attributedString[$0].foregroundColor = .blue }

但关键的一点是我们现在可以使用原生Regex文字包围着/字符,如上所示。


在 5.7 之前的 Swift 版本中,人们会使用NSRegularExpression https://developer.apple.com/documentation/foundation/nsregularexpression/. E.g.:

let range = NSRange(location: 0, length: string.count)
try! NSRegularExpression(pattern: "\\d+").enumerateMatches(in: string, range: range) { result, _, _ in
    guard let range = result?.range else { return }
    attributedString.setAttributes(attributes, range: range)
}

因为正则表达式反斜杠位于字符串内部,所以必须用另一个反斜杠对其进行转义(这就是其中有两个反斜杠的原因)。或者您可以使用扩展字符串分隔符,替换"\\d+" with #"\d+"#.


就我个人而言,在 Swift 5.7 之前,我发现有一个返回 Swift 范围数组的方法很有用,即[Range<String.Index>]:

extension StringProtocol {
    func ranges<T: StringProtocol>(of string: T, options: String.CompareOptions = []) -> [Range<Index>] {
        var ranges: [Range<Index>] = []
        var start: Index = startIndex
        
        while let range = range(of: string, options: options, range: start ..< endIndex) {
            ranges.append(range)
            
            if !range.isEmpty {
                start = range.upperBound               // if not empty, resume search at upper bound
            } else if range.lowerBound < endIndex {
                start = index(after: range.lowerBound) // if empty and not at end, resume search at next character
            } else {
                break                                  // if empty and at end, then quit
            }
        }
        
        return ranges
    }
}

然后你可以像这样使用它:

let string = "Hello world, there are 09 continents and 195 countries."
let ranges = string.ranges(of: "[0-9]+", options: .regularExpression)

然后你就可以map the Range to NSRange。回到最初的示例,如果您想在某些属性字符串中将这些数字设为粗体:

string.ranges(of: "[0-9]+", options: .regularExpression)
    .map { NSRange($0, in: string) }
    .forEach { attributedString.setAttributes(boldAttributes, range: $0) }

资源:

  • Swift 5.7 and later:
    • WWDC 2022 视频认识 Swift 正则表达式 https://developer.apple.com/videos/play/wwdc2022/110357/
    • WWDC 2022 视频Swift Regex:超越基础知识 https://developer.apple.com/videos/play/wwdc2022/110358/
    • 使用 Swift 进行黑客攻击:常用表达 https://Regular%20expressions%20Available%20from%20Swift%205.7
  • Swift before 5.7:
    • 使用 Swift 进行黑客攻击:如何在 Swift 中使用正则表达式 https://www.hackingwithswift.com/articles/108/how-to-use-regular-expressions-in-swift
    • NSHipster:Swift 中的正则表达式 https://nshipster.com/swift-regular-expressions/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从完整字符串 iOS swift 中找到字符串的多个 NSRange 的相关文章

  • UIApplication.shared.delegate 相当于 SceneDelegate xcode11?

    我在 SceneDelegate 中定义了一个 let 属性 我希望一些 ViewController 能够在场景中访问它 在 UIKit 中 我可以像这样访问 App Delegate 属性 UIApplication shared de
  • 未捕获的 Kotlin 异常:kotlin.native.In CorrectDereferenceException:非法尝试访问非共享

    我尝试使用 Kotlin MPP Multiplatform 开发 Android 和 iOS 之间的共享库 但我面临着 iOS 中线程的问题 对于我在 iOS 中的应用程序 我在主线程中建立了对象 但它可能调用其他线程中的函数并抛出此异常
  • 如何无限地每1分钟运行一个iOS应用程序?

    我制作了一个应用程序 需要每 1 分钟向服务器发送一次位置和状态更新 我尝试了以下方法 但没有一个能帮助我 有什么解决办法吗 1 NSTimer 很多人建议这样做 但问题出在后台模式上 它只能工作 20 分钟 该应用程序停止发送数据后 2
  • iOS 11 浮动 TableView 标题

    有一个应用程序包含多个部分 展开 时每个部分有几行 折叠 时没有 每个部分都有一个部分标题 使用以下子类重用它们UITableViewHeaderFooterView等等 到目前为止一切顺利 然后在 iOS 11 中 我使用了可视化调试器
  • 使用prepareForSegue传递数据

    我试图将数据从viewController 1传递到viewController2 我有2个按钮和1个segue 因此有一个segue标识符 这2个按钮 按下时每个按钮应显示 1个标签用于显示标题 1个textView用于显示定义 我很难显
  • CustomNSError 协议有什么作用以及为什么我应该采用它?

    什么是CustomNSError协议的用途以及为什么我应该采用它 Apple提供的文档仅指出 描述错误类型 具体提供域 代码和 用户信息字典 我已经在谷歌上搜索过 但找不到与我的问题相关的任何内容 每种类型都符合Error协议是隐含地桥接的
  • let/var 如何解决可变性? [复制]

    这个问题在这里已经有答案了 我没有任何问题 我只是想对有关可变性的问题进行一些澄清 在 Objective C 中我们会使用例如NSMutableArray得到一个可变数组和NSArray得到一个不可变的 我对两者的内部运作了解不多 但据我
  • 如何在 Swift 中使用 CoreBluetooth 更新 BLE 设备的电池电量?

    func peripheral peripheral CBPeripheral didDiscoverCharacteristicsFor service CBService error Error for c in service cha
  • Swift:检查 UISearchBar.text 是否包含 url

    如何检查 UISearchBar text 是否包含 URL 我想做这样的事情 if searchBar text NSTextCheckingType Link 但我收到错误 String is not convertible to NS
  • iOS Swift 在后台下载大量小文件

    在我的应用程序中 我需要下载具有以下要求的文件 下载大量 例如 3000 个 小 PNG 文件 例如 5KB 逐个 如果应用程序在后台继续下载 如果图像下载失败 通常是因为互联网连接丢失 请等待 X 秒然后重试 如果失败Y次 则认为下载失败
  • 如何将CIFilter应用到UIView上?

    根据Apple docs 过滤属性CALayer不支持iOS 当我使用正在申请的应用程序之一时CIFilter to UIView即 Splice Funimate 和 Artisto 的视频编辑器 Videoshow FX 这意味着我们可
  • xcode 9.0.1 / swift 4,没有使用 Objective-C 选择器 'onClick:forEvent:' 声明的方法 [重复]

    这个问题在这里已经有答案了 I use swift 4为了构建我的 UI 我创建了一个UIButton并想为其添加一个目标 但编译器会抛出警告 No method declared with Objective C selector onC
  • 在 Swift 中以编程方式为 iOS 制作带有名字首字母的图像,例如 Gmail

    我需要在 UITableView 中显示与其姓名相对应的每个用户的个人资料图片 在下载图像之前 我需要显示一张带有他名字的第一个字母的图像 就像在 GMail 应用程序中一样 如何在 Swift for iOS 中以编程方式执行此操作 不需
  • iOS Swift 和 reloadRowsAtIndexPaths 编译错误

    我与 xCode Swift 陷入僵局并刷新 UITableView 的单行 这条线有效 self tableView reloadData 而这条线没有 self tableView reloadRowsAtIndexPaths curr
  • WKWebview 中的 iCLoud 文档选择器关闭容器视图

    我有一个 WKWebview 加载基于 Web 的 UI 我希望用户能够从其 iCloud 文档上传文件 我已授予正确的权限 并且可以浏览 iCloud 文档 但是 当我选择文件或单击取消按钮时 文档选择器视图也会关闭 WKWebview
  • 具有动态警报正文的快速本地通知

    所以我可以创建一个像这样的本地通知 var localNotification UILocalNotification localNotification fireDate NSDate timeIntervalSinceNow 7 loc
  • 如何在 swiftUI (macOS) 中检测按键按下和释放

    除了标题之外没什么可说的 我希望能够在按下按键和释放按键时 在 macOS 上 在 swiftUI 视图中执行操作 在 swiftUI 中是否有任何好的方法可以做到这一点 如果没有 有什么解决方法吗 不幸的是 键盘事件处理是其中一个令人痛苦
  • 如何右对齐 UILabel?

    Remark 实施 myLabel textAlignment right does not解决了我的问题 这不是我所要求的 我想要实现的是让标签对齐右对齐 为了更清楚地说明 这就是如何left对齐外观 就是这样justify对齐外观 if
  • 对成员“buildBlock()”的引用不明确

    我一直在尝试使用 Swift UI 为 iOS 13 制作一个应用程序 但我不断收到这个奇怪的错误 对成员 buildBlock 的引用不明确 无论我做什么 错误都不会消失 我尝试一次对代码段进行注释 以查看哪一部分可能导致了问题 但唯一有
  • iOS 防止计时器 UILabel 在数字变化时“晃动”

    我有一个UILabel它以以下格式显示计时器的输出MM ss SS 分 秒 厘秒 但是随着厘秒宽度的变化 它从左向右 摇动 例如 11 比 33 窄 有什么办法可以减轻这种情况吗 我尝试过将其居中 给它固定的宽度 但它们似乎没有帮助 从iO

随机推荐