【问题标题】:What is an efficient way to search a string for the first of a set of delimiters?在字符串中搜索一组分隔符中的第一个的有效方法是什么?
【发布时间】:2015-05-04 22:23:14
【问题描述】:

我有一个 UTF-8 编码的字符串,我想遍历它, 将其拆分为多个分隔符之一。我也需要知道 哪个分隔符匹配,因为每个分隔符都有特定的含义。

示例用法:

algorithm("one, two; three") => Match("one")
algorithm(", two; three")    => Delimiter(",")
algorithm(" two; three")     => Match(" two")
algorithm("; three")         => Delimiter(";")
algorithm(" three")          => Match(" three")   

附加信息:

  • 我的分隔符都是单个ASCII字符,所以优化了 需要的算法是可能的。
  • 处理 UTF-8 子字符串的解决方案也将不胜感激, 但不是必需的。
  • 我计划多次调用该方法,并且可能在紧张的情况下 循环,因此理想的算法不需要分配任何内存。
  • 算法应该返回第一个匹配的字符串或分隔符 我可以在下一次迭代中重新开始搜索。
  • 理想的算法天生就知道它是否返回匹配或 分隔符,但可以在事后检查。

我的目标语言是 Rust,但我希望得到任何答案 具有类似较低层次焦点的语言。伪代码也很好, 只要它能够识别 UTF-8 文本的真实性。解决方案 使用深奥的十六进制技巧或 SIMD 指令也是合适的,但可能需要更多解释才能让我理解 ^_^。

【问题讨论】:

  • 我一定错过了什么。 Rust 是否提供了一种遍历 utf-8 字符串字符的方法?一直这样做,直到您击中第一个匹配项或分隔符。
  • @ProgrammerPerson 这是我当前的解决方案和有效答案。我问的主要是因为我使用的似乎是一个幼稚的解决方案,并且它在我的应用程序中占用了合理的时间。因此,我希望有一些我没有想到的更聪明的东西。

标签: string algorithm search utf-8


【解决方案1】:

对于特定于处理器的解决方案,具有 SSE4.2 的 X86-64 处理器包含 PCMPxSTRx 系列指令。这些说明可用的模式之一是Equal Any

arg1 是一个字符集,arg2 是要搜索的字符串。如果arg2[i]arg1 表示的集合中,则IntRes1[i] 设置为1

基本算法很简单:

  1. 用最多 16 个单字节填充 XMM 寄存器以搜索(针)。
  2. rax中设置针字节数。
  3. 计算字符串开头的内存地址,包括偏移量。
  4. 设置rdx中的haystack字节数。
  5. 使用适当的控制字节调用PCMPxSTRx
  6. 检查ecx 或控制代码标志之一的结果。
  7. 如果没有匹配项并且仍有字符串要搜索,则增加偏移量并循环。

但是有a complication around page boundaries。也就是说,PCMPxSTRx 指令将总是读取 16 字节的数据。如果您读入受保护的内存页面,这可能会导致分段错误。一种解决方案是将所有读取对齐到字符串的 end,并在开头处理剩余字节。在开始上述算法之前,使用类似:

  1. ~0xF 屏蔽字符串的起始地址。这会清除所有低位。
  2. 对前 16 个字节使用 PCMPxSTRM 指令(具有与上述算法类似的设置)。这将返回匹配字符的掩码。您可以移动掩码以忽略不属于您的字符串的前导字符。
  3. 如果没有匹配并且还有更多字符串要搜索,则启动上述算法。

您可以在我的Rust library Jetscii 中查看此算法的完整示例。内联汇编用于调用PCMPxSTRx 指令。

【讨论】:

    猜你喜欢
    • 2012-03-23
    • 2018-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 2021-07-16
    • 1970-01-01
    相关资源
    最近更新 更多