搜索字符串中第一个分隔符的有效方法是什么?

时间:2015-05-04 22:23:15

标签: string algorithm search utf-8

我有一个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指令也是合适的,但可能需要更多解释才能理解^ _ ^。

1 个答案:

答案 0 :(得分:1)

对于特定于处理器的解决方案,带有SSE4.2的X86-64处理器包含PCMPxSTRx系列指令。这些说明中提供的模式之一是等于任何

  

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

基本算法很简单:

  1. 使用最多16个单字节填充XMM寄存器以搜索(针)。
  2. arg1
  3. 中设置针数字节数
  4. 计算字符串开头的内存地址,包括偏移量。
  5. rax中设置haystack字节数。
  6. 使用适当的控制字节调用rdx
  7. 检查PCMPxSTRx或其中一个控制代码标记的结果。
  8. 如果没有匹配且仍有字符串需要搜索,请增加偏移并循环。
  9. 但是有a complication around page boundaries。也就是说,ecx指令将始终读取16个字节的数据。如果您读入受保护的内存页,则可能会导致分段错误。解决方案是将所有读取与字符串的 end 对齐,并在开头处理剩余的字节。在开始上述算法之前,请使用以下内容:

    1. 使用PCMPxSTRx屏蔽字符串开头的地址。这清除了所有低位。
    2. 对前16个字节使用~0xF指令(使用与上述算法类似的设置)。这将返回匹配字符的掩码。您可以移动蒙版以忽略不属于字符串的前导字符。
    3. 如果没有匹配且剩下更多字符串要搜索,请启动上述算法。
    4. 您可以在我的Rust library Jetscii中查看此算法的完整示例。内联汇编用于调出PCMPxSTRM指令。