用 ctre-unicode 匹配一组 unicode 字符

Match a set of unicode characters with ctre-unicode

说,我有一个字符串

char8_t text[] = u8"• test\n - two\n ••    three\n-• four\n";

我想用单个 space 替换任意数量的连续空白字符 -。我尝试了以下方法:

char8_t* b = text + std::size(text)-1;
for (char8_t* r = text;;) {
  auto m = ctre::search<u8R"([\s\-•]+)">(r,b);
  if (!m) break;
  char8_t* w = m.begin();
  r = m.end();
  if (r==b) {
    b = w;
    break;
  }
  *w++ = ' ';
  if (w!=r) {
    memmove(w,r,b-r);
    b -= r-w;
    r = w;
  }
}
*b = '[=11=]';

cout << ((char*)text) << endl;

但这会导致

• test two •• three • four

我包括 Hana's GitHub repo 中的 <ctre-unicode.hpp>

这是错误还是预期的行为?

起初,我认为问题可能出在将 放入 [] 中,因为可能 [] 只接受单字节字符和转义序列,但我明白了(?:[\s\-]|•)+ 的输出与原始 [\s\-•]+ 相同。 \P{L}+ 结果,我假设是,只删除了一些包含 字符的字节:

� test two � � three � four

这是神栓 link

我对 库知之甚少,所以我可能在下面使用了一些笨拙的结构,但希望它足够好以达到某个目的。我已经内联评论以解释它在做什么。

#include <ctre-unicode.hpp>

#include <algorithm>
#include <cstring>
#include <iostream>
#include <iterator>
#include <string_view>

template<class T>
T* get_nonconst_ptr(T* b, const T* e) {
    // a helper to get a non-const pointer to `e`
    return b + std::distance(const_cast<const T*>(b), e);
}

int main() {
    char8_t text[] = u8"• test\n - two\n ••    three\n-• four\n";    

    std::u8string_view tv = text; // a view over the part of `text` left to search

    while(true) {
        auto m = ctre::search<u8R"([\s\-•]+)">(tv);
        if(!m) break; // no match, we're done

        // where to move to
        auto dest = get_nonconst_ptr(text, m.data());

        // where to move from
        auto src = dest + m.size();
        *dest++ = ' '; // replace what was matched with a single space

        // get pointer to end        
        auto end = get_nonconst_ptr(text, tv.end());

        std::move(src, end + 1, dest); // do the move, incl. null terminator

        // a new view over the rest of `text`:
        tv = std::u8string_view(dest, std::distance(src, end));
    }

    std::cout << reinterpret_cast<unsigned char*>(text) << '\n';
}

输出:

 test two three four

Live demo

我在 github 仓库中打开了一个 issue,作者回复了。

Unicode 操作模式是通过使用 ctre::utf8_iterator 在内部实现的。但在当前的实现中,仅当 search 函数接收 std::u8string_view 作为参数时才会触发 utf8_iterator 的使用。在当前的实现中,一对 char8_t* 不会使 search 使用 utf8_iterator.

这就是为什么 Unicode example in the readme and Ted Lyngmo's 都在 utf8 模式下工作,但我的原始代码在字节模式下工作。