Swift 5:具有最大 UTF-8 长度的字符串前缀

2024-01-15

我有一个可以包含任意 Unicode 字符的字符串,我想得到一个prefix该字符串的UTF-8编码长度尽可能接近32字节,同时仍然是有效的 UTF-8 并且不改变字符的含义(即不切断扩展字素簇)。

考虑一下这个CORRECT例子:

let string = "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}\u{1F1EA}\u{1F1FA}"
print(string)                    // ????????????????????????????????????
print(string.count)              // 2
print(string.utf8.count)         // 36

let prefix = string.utf8Prefix(32)  // <-- function I want to implement 
print(prefix)                    // ????????????????????????????
print(prefix.count)              // 1
print(prefix.utf8.count)         // 28

print(string.hasPrefix(prefix))  // true

这个例子是WRONG执行:

let string = "ar\u{1F3F4}\u{200D}\u{2620}\u{FE0F}\u{1F3F4}\u{200D}\u{2620}\u{FE0F}\u{1F3F4}\u{200D}\u{2620}\u{FE0F}"
print(string)                    // ar????‍☠️????‍☠️????‍☠️
print(string.count)              // 5
print(string.utf8.count)         // 41

let prefix = string.wrongUTF8Prefix(32)  // <-- wrong implementation 
print(prefix)                    // ar????‍☠️????‍☠️????
print(prefix.count)              // 5
print(prefix.utf8.count)         // 32

print(string.hasPrefix(prefix))  // false

有什么优雅的方法可以做到这一点? (除了反复试验)


我发现String and String.UTF8View共享相同的索引,因此我设法创建一个非常简单(且高效?)的解决方案,我认为:

extension String {
    func utf8Prefix(_ maxLength: Int) -> Substring {
        if self.utf8.count <= maxLength {
            return Substring(self)
        }

        var index = self.utf8.index(self.startIndex, offsetBy: maxLength+1)
        self.formIndex(before: &index)
        return self.prefix(upTo: index)
    }
}

解释(假设maxLength == 32 and startIndex == 0):

第一种情况(utf8.count <= maxLength)应该很清楚,那就是不需要工作的地方。
对于第二种情况,我们首先获取 utf8-index33,这是

  • A:字符串的 endIndex(如果它的长度正好是 33 个字节),
  • B:字符开头的索引(前一个字符的 33 个字节之后)
  • C:字符中间某处的索引(在

因此,如果我们现在将索引向后移动一个字符(使用formIndex(before:))这将跳转到之前的第一个扩展字素簇边界index如果 A 和 B 是该字符之前的一个字符,而在 C 中则是该字符的开头。
无论如何,现在将保证 utf8 索引最多为32并且在扩展的字素簇边界处,所以prefix(upTo: index)将安全地创建长度≤32的前缀。


……但这并不完美。
理论上这也应该始终是最佳解决方案,即前缀的count尽可能接近maxLength但有时当字符串以由多个 Unicode 标量组成的扩展字素簇结尾时,formIndex(before: &index)返回的字符比所需的字符多,因此前缀会变短。我不太清楚为什么会这样。

编辑:一个不太优雅但完全“正确”的解决方案是这样的(仍然只有 O(n)):

extension String {
    func utf8Prefix(_ maxLength: Int) -> Substring {
        if self.utf8.count <= maxLength {
            return Substring(self)
        }

        let endIndex = self.utf8.index(self.startIndex, offsetBy: maxLength)
        var index = self.startIndex
        while index <= endIndex {
            self.formIndex(after: &index)
        }
        self.formIndex(before: &index)
        return self.prefix(upTo: index)
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swift 5:具有最大 UTF-8 长度的字符串前缀 的相关文章

  • 如何使用逗号和行分隔符对字符串进行标记

    我正在 Swift 中制作一个简单的 String Tokenizer 就像在 Java 中一样 但这对我来说确实不起作用 我的数据源中每行的末尾用 分隔 数据用逗号分隔 例如 字符串 1 字符串 2 字符串 3 字符串 1 字符串 2 字
  • 无法在 xcode 8 beta 6 上编译 AWS CustomIdentityProvider

    我在 iOS 应用程序中使用 Amazon Cognito 和 Facebook 登录 直到 beta 5 为止此代码从这个SO线程 https stackoverflow com questions 37597388 aws cognit
  • Swift 中通过可选绑定进行安全(边界检查)数组查找?

    如果我在 Swift 中有一个数组 并尝试访问超出范围的索引 则会出现一个不足为奇的运行时错误 var str Apple Banana Coconut str 0 Apple str 3 EXC BAD INSTRUCTION 但是 我会
  • 自动生成的 Swift 桥接标头中“找不到接口声明”

    我当前的项目包含 Swift 和 Objective C 代码 两种类型的源文件都使用另一种语言的代码 当我进行完全清理并重新编译时 几乎每个 Swift 类声明都出现错误Module Swift h 形式为 Cannot find int
  • C++中判断unicode字符是全角还是半角

    我正在编写一个终端 控制台 应用程序 该应用程序应该包装任意 unicode 文本 终端通常使用等宽 固定宽度 字体 因此要换行文本 只需计算字符数并观察单词是否适合一行并采取相应的操作 问题是 Unicode 表中的全角字符在终端中占用了
  • 如何在 SwiftUI 中延迟动画?

    我想为两个文本字段设置动画 第二个字段有延迟 但它不起作用 没有延迟 它们同时从位置 100 动画到 0 这是代码 State private var offset CGFloat 100 State private var offset2
  • 出现错误:字符串未被识别为 C# 中的有效日期时间

    出现如下错误 mscorlib dll 中发生类型为 System FormatException 的未处理异常附加信息 字符串未被识别为有效的日期时间 我正在使用这段代码 string datetime DateTime Parse en
  • 如何在 iOS swift 中集成 Google Pay?

    嗨 朋友们 我搜索过有关 iOS swift 中谷歌支付集成的信息 我没有找到任何相关的解决方案 请帮助我如何解决这个问题 如果有任何链接或示例 请提供链接并指导我 谢谢 这是关于在印度发起 Google Pay 操作的问题吗 例如 使用
  • Java在字符串中看不到空格[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 因此 我正在尝试解析一些具有多行文本的文本文件 我的工作是检查所有单词并将其打印在文件中 因此 我读取了所有行 循环遍历它们并用空格分隔每
  • 本地“关闭”binmode(STDOUT, ":utf8")

    我的脚本开头有以下块 usr bin perl5 w use strict binmode STDIN utf8 binmode STDOUT utf8 binmode STDERR utf8 在某些子程序中 当存在其他编码 来自远程子程序
  • 在 PHP 中比较字符串的方式与 MySQL 相同

    我将 varchar 存储在 utf8 MySQL 表中并使用 utf8 general ci 排序规则 我在 varchar 上有一个唯一索引 我想在 PHP 中进行字符串比较 这相当于 MySQL 对索引所做的操作 一个具体的例子是 我
  • 领域列表未存储在 Swift 4.2 的发布配置中

    我刚刚构建了我的应用程序的最新版本 并且遇到了一个问题List我的所有领域对象上的 s 都没有被存储 这是一些示例代码 Object public class ReportItem Object objc dynamic var id St
  • 如何在 Swift 中退出“DispatchQueue.main.asyncAfter”

    我想在调用 deinit 时退出 DispatchQueue main asyncAfter 子视图 swift DispatchQueue main asyncAfter deadline now 5 0 self doSomething
  • 排除 Realm 模型类

    我的应用程序中配置了两个领域文件 我想存储我的Log将模型与其他模型分开保存为单独的文件 我的问题是我也看到了我的Log我不想要的默认 Realm 文件中的模型类 如何从给定的 Realm 文件中排除特定的模型类 我使用主 Realm 文件
  • 更改 UIAlertController 的标题字体大小

    我正在尝试更改标题fontSize in an UIAlertController 但我无法管理如何设置我的NSMutableAttributedString to the title 财产 所以我一直在创造NSMutableAttribu
  • 如何更改某些功能以兼容 iOS 10 或更低版本的 Snapchat 中的某些功能,例如相机视图控制器

    我正在制作一个视图控制器来制作像 snapchat 相机一样的相机视图控制器 我下面的代码在 iOS 11 或更高版本上完美运行 老实说 我并没有真正掌握我的代码 因为我只是按照这个像相机视图控制器这样的 snapchat 的教程进行操作
  • 从钥匙串保存和加载 |斯威夫特[重复]

    这个问题在这里已经有答案了 如何简单地将字符串存储在钥匙串中并在需要时加载 有几种SO解决方案 主要参考Git repo 但我需要最新 Swift 上最小和最简单的解决方案 当然 我不想添加 git 框架来简单地在我的项目中存储密码 有类似
  • 将字符串转换为字符并按降序排序(ascii)

    我正在创建一个程序 该程序将使用户输入整数 一个接一个 存储在数组中并按降序显示整数 该程序还要求用户输入一个字符串 使用以下命令将其转换为字符string toCharArray 我已经正确地按降序显示整数 问题是我不知道如何按降序显示字
  • 以编程方式进行排序时检索 ViewController 堆栈

    static func showMenuView parentVC UIViewController let storyboard UIStoryboard name Main bundle nil let resultController
  • 将整数转换为特定格式的十六进制字符串

    我是 python 新手 有以下问题 我需要将整数转换为 6 个字节的十六进制字符串 例如 281473900746245 gt xFF xFF xBF xDE x16 x05 十六进制字符串的格式很重要 int 值的长度是可变的 格式 0

随机推荐