如何解析 Swift 中的 twitch IRC 表情?

How to parse twitch IRC emotes in Swift?

我正在尝试解析 Twitch IRC 表情并将其从字符串中提取出来。 Twitch IRC 消息提供了一个范围,它是一个表情符号在字符串中的位置。示例:

string="Kappa abcdef"; range start=0; range end=4

表示表情 Kappa 位于字符串“Kappa abcdef”中的索引 0 到 4。

这是我的函数,它将 return 基于范围的表情:

func extractEmoteName(from message: String, rangeStart: Int, rangeEnd: Int) -> String? {
    guard
        let indexStart = message.index(message.startIndex, offsetBy: rangeStart, limitedBy: message.endIndex),
        let limitIndex = message.index(message.endIndex, offsetBy: -1, limitedBy: message.startIndex),
        let indexEnd = message.index(message.startIndex, offsetBy: rangeEnd, limitedBy: limitIndex)
    else {
        print("out of bounds")
        return nil
    }
    
    return String(message[indexStart ... indexEnd])
}

在示例字符串上使用它:extractEmoteName(from: "Kappa abcdef", rangeStart: 0, rangeEnd: 4) 将 return Kappa 作为结果。

我在处理包含具有多个 unicode 标量的表情符号的字符串时遇到问题:

string="⚠️ Kappa"; range start=3; range end=7

提取函数的结果是nil:

extractEmoteName(from: "⚠️ Kappa", rangeStart: 3, rangeEnd: 7) // prints "out of bounds"

同时,由于 Twitch 提供的范围不同,具有单个标量表情的消息可以很好地解析:

string=" Kappa"; range start=2; range end=6

extractEmoteName(from: " Kappa", rangeStart: 2, rangeEnd: 6) // returns "Kappa"

extractEmoteName 中应该更改哪些内容才能使其适用于所有表情符号字符?

你需要使用unicodeScalars,它将代表unicode标量中的字符串:

func extractEmoteName(from input: String, rangeStart: Int, rangeEnd: Int) -> String? {
    let message = input.unicodeScalars
    
    guard
        let indexStart = message.index(message.startIndex, offsetBy: rangeStart, limitedBy: message.endIndex),
        let limitIndex = message.index(message.endIndex, offsetBy: -1, limitedBy: message.startIndex),
        let indexEnd = message.index(message.startIndex, offsetBy: rangeEnd, limitedBy: limitIndex)
    else {
        print("out of bounds")
        return nil
    }
    
    return String(message[indexStart ... indexEnd])

你可以通过计算标量来做到这一点。

func extractEmoteName(from message: String, rangeStart: Int, rangeEnd: Int) -> String? {
    guard rangeStart >= 0 && rangeStart <= rangeEnd else {
        return nil
    }
    let scalars = message.unicodeScalars
    let start = scalars.index(scalars.startIndex, offsetBy: rangeStart)
    let end = scalars.index(scalars.startIndex, offsetBy: rangeEnd)
    let nameScalars = scalars[start...end]
    return String(nameScalars)
}