MSVC2015(C++11)下用std::regex_match匹配自定义字符类的问题
问题分析与解决方案
编译错误的核心原因:
- 你使用的
std::regex是std::basic_regex<char>的别名,与迭代器指向的MyChar类型字符不匹配; - 即使换成
std::basic_regex<char32_t>,标准库正则函数也无法直接处理MyChar迭代器,因为其value_type不是char32_t。
以下是两种无需转换为std::u32string的实现方案:
方案一:迭代器适配器(零拷贝,推荐)
实现轻量级迭代器适配器,将MyChar迭代器包装为指向char32_t的迭代器,全程无内存分配与拷贝:
#include <regex> #include <iterator> #include <vector> struct MyChar { char32_t c; int color_id; MyChar(char32_t wc) : c(wc), color_id(1) {} operator char32_t()const { return c; } MyChar() : c(0), color_id(1) {} MyChar(const MyChar&) = default; MyChar& operator=(const MyChar& cc) { c = cc.c; color_id = cc.color_id; return *this; } bool operator==(const MyChar& c2)const { return c == c2.c; } bool operator!=(const MyChar& c2)const { return c != c2.c; } }; // 迭代器适配器:将MyChar迭代器转换为char32_t迭代器 template <typename Iter> struct MyCharToChar32Iter : public std::iterator<std::bidirectional_iterator_tag, const char32_t> { Iter base; MyCharToChar32Iter(Iter it) : base(it) {} const char32_t& operator*() const { return base->c; } const char32_t* operator->() const { return &base->c; } MyCharToChar32Iter& operator++() { ++base; return *this; } MyCharToChar32Iter operator++(int) { auto tmp = *this; ++base; return tmp; } MyCharToChar32Iter& operator--() { --base; return *this; } MyCharToChar32Iter operator--(int) { auto tmp = *this; --base; return tmp; } bool operator==(const MyCharToChar32Iter& other) const { return base == other.base; } bool operator!=(const MyCharToChar32Iter& other) const { return base != other.base; } }; int main(int, char**) { std::vector<MyChar> line = {U'H', U'e', U'l', U'l', U'o', U' ', U'W', U'o', U'r', U'l', U'd'}; // 使用char32_t版本的正则表达式,模式串用U""前缀声明 std::basic_regex<char32_t> rx(U"\\b(hello|world)\\b", std::regex::icase); // 包装原迭代器 auto first = MyCharToChar32Iter<decltype(line.begin())>(line.begin()); auto last = MyCharToChar32Iter<decltype(line.end())>(line.end()); // match_results的迭代器类型需与适配后的迭代器一致 std::match_results<decltype(first)> matches; if (std::regex_match(first, last, rx, matches)) { // 如需获取原MyChar序列的匹配范围,通过base()方法反向获取原迭代器 auto start_iter = matches[0].first.base(); auto end_iter = matches[0].second.base(); } }
关键说明:
- 适配器仅包装原迭代器,解引用时直接返回
MyChar的c成员,无额外开销; - 若需操作原
MyChar对象,可通过match_results中迭代器的base()方法获取原vector的迭代器; - 正则表达式必须使用
std::basic_regex<char32_t>,模式串需对应char32_t类型。
方案二:特化std::char_traits<MyChar>(需谨慎)
通过特化标准库的char_traits模板,让正则函数直接识别MyChar作为字符类型。注意:特化标准库模板需严格遵循标准要求,且MSVC2015可能存在兼容性限制:
#include <regex> #include <vector> #include <cstring> #include <cwchar> struct MyChar { char32_t c; int color_id; MyChar(char32_t wc) : c(wc), color_id(1) {} operator char32_t()const { return c; } MyChar() : c(0), color_id(1) {} MyChar(const MyChar&) = default; MyChar& operator=(const MyChar& cc) { c = cc.c; color_id = cc.color_id; return *this; } bool operator==(const MyChar& c2)const { return c == c2.c; } bool operator!=(const MyChar& c2)const { return c != c2.c; } }; // 特化char_traits<MyChar>,实现标准要求的所有静态方法 namespace std { template<> struct char_traits<MyChar> { using char_type = MyChar; using int_type = int; using off_type = streamoff; using pos_type = streampos; using state_type = mbstate_t; static void assign(char_type& a, const char_type& b) { a = b; } static bool eq(const char_type& a, const char_type& b) { return a.c == b.c; } static bool lt(const char_type& a, const char_type& b) { return a.c < b.c; } static int compare(const char_type* s1, const char_type* s2, size_t n) { for (size_t i = 0; i < n; ++i) { if (s1[i].c != s2[i].c) { return s1[i].c < s2[i].c ? -1 : 1; } } return 0; } static size_t length(const char_type* s) { size_t len = 0; while (s[len].c != 0) ++len; return len; } static const char_type* find(const char_type* s, size_t n, const char_type& a) { for (size_t i = 0; i < n; ++i) { if (s[i].c == a.c) return &s[i]; } return nullptr; } static char_type* move(char_type* s1, const char_type* s2, size_t n) { return static_cast<char_type*>(memmove(s1, s2, n * sizeof(char_type))); } static char_type* copy(char_type* s1, const char_type* s2, size_t n) { return static_cast<char_type*>(memcpy(s1, s2, n * sizeof(char_type))); } static char_type* assign(char_type* s, size_t n, char_type a) { for (size_t i = 0; i < n; ++i) s[i] = a; return s; } static char_type to_char_type(const int_type& c) { return MyChar(static_cast<char32_t>(c)); } static int_type to_int_type(const char_type& c) { return static_cast<int>(c.c); } static bool eq_int_type(const int_type& c1, const int_type& c2) { return c1 == c2; } static int_type eof() { return static_cast<int_type>(U'\0'); } static int_type not_eof(const int_type& c) { return c != eof() ? c : 1; } }; } int main(int, char**) { std::vector<MyChar> line = {U'H', U'e', U'l', U'l', U'o', U' ', U'W', U'o', U'r', U'l', U'd'}; // 将u32string模式串转换为MyChar序列构造正则 std::u32string pattern = U"\\b(hello|world)\\b"; std::vector<MyChar> rx_pattern(pattern.begin(), pattern.end()); std::basic_regex<MyChar> rx(rx_pattern.begin(), rx_pattern.end(), std::regex::icase); std::match_results<std::vector<MyChar>::const_iterator> matches; if (std::regex_match(line.begin(), line.end(), rx, matches)) { // 直接使用matches中的原MyChar迭代器 } }
关键说明:
- 需实现
char_traits要求的所有静态方法,代码量较大; - 构造正则时需将
u32string模式串转换为MyChar序列,该转换开销极小且可提前完成; - 该方案在MSVC2015中需测试验证兼容性。
内容的提问来源于stack exchange,提问作者KungPhoo
相关产品推荐
相关产品推荐

