我正在编写一个库来读取一些特定的文件格式。使用内存映射文件(boost::interprocess
模板)读取文件。在这些文件上,我必须用std::regex
做一些搜索。为了避免不必要的复制,我想直接使用内存映射文件(作为c风格的字符数组)。
经过一番研究,我提出了以下两种方法:
- 使用
streambuf
对象的pubsetbuf
方法 - 使用
char*
指针作为迭代器
,但是由于第一种方法的实现对于STL供应商来说是可选的,所以我坚持使用第二种方法。由于std::string::iterator
的构造函数被声明为私有,并且整个迭代器的实现似乎也是特定于供应商的。我写了自己的迭代器:
template<typename T>
class PointerIterator: std::iterator<std::input_iterator_tag, T> {
public:
PointerIterator(T* first, std::size_t count): first_(first), last_(first + count) {}
PointerIterator(T* first, T* last): first_(first), last_(last) {}
class iterator {
public:
iterator(T* p): ptr_(p) {}
iterator(const iterator& it): ptr_(it.ptr_) {}
iterator& operator++() {
++ptr_;
return *this;
}
iterator operator++(int) {
iterator temp(*this);
++ptr_;
return temp;
}
bool operator==(const iterator& it) { return ptr_ == it.ptr_; }
bool operator!=(const iterator& it) { return ptr_ != it.ptr_; }
T& operator*() { return *ptr_; }
private:
T* ptr_;
};
iterator begin() {
return iterator(first_);
}
iterator end() {
return iterator(last_);
}
private:
T* first_;
T* last_;
};
迭代器可以工作,但是对于std::regex_search
方法(或其他与char相关的STL方法),它必须与STL迭代器的类型相同。
是否有一些通用的方法将我的迭代器转换为STL的(可移植到STL实现上),或者用另一种我没有提到的方法实现整个事情?
编辑:使用std::regex_search
:
std::regex re(...);
boost::interprocess::mapped_region region(...);
char* first = static_cast<char*>(region.get_address());
char* last = first + 5000;
// ...
PointerIterator<char> wrapper(first, last);
std::smatch match;
while (std::regex_search(wrapper.begin(), wrapper.end(), match, re)) { // Error: No matching function call to 'regex_search'
// do something
}
谢谢
std::smatch
的定义是std::match_results
的专门化。这个特化使用string::const_iterator
作为传递给std::match_results
的模板实参中的迭代器类型。这要求传递给std::regex_search
的begin和end参数也必须是string::const_iterator
类型的。
char
指针指向的缓冲区,可以使用std::cmatch
或std::match_results
并显式指定迭代器类型。在下面的两个示例中,我保留了使用PointerIterator
来提供直接应用于当前代码库的解决方案。我还包含了一个独立的示例,如果您想要消除自定义迭代器类的使用,您可以引用它。
PointerIterator<char> wrapper(first, last);
std::cmatch match; // <<--
while (std::regex_search(wrapper.begin(), wrapper.end(), match, re))
{
// do something
}
…使用std::match_results
代替。
PointerIterator<char> wrapper(first, last);
std::match_results<const char*> match; // <<--
while (std::regex_search(wrapper.begin(), wrapper.end(), match, re))
{
// do something
}
下面是一个独立的例子,应该提供一些成文的澄清。它基于cppreference.com上的示例,并使用const char*
而不是std::string
作为搜索目标。
#include <regex>
#include <iostream>
int main()
{
const char *haystack = "Roses are #ff0000";
const int size = strlen(haystack);
std::regex pattern(
"#([a-f0-9]{2})"
"([a-f0-9]{2})"
"([a-f0-9]{2})");
std::cmatch results;
std::regex_search(haystack, haystack + size, results, pattern);
for (size_t i = 0; i < results.size(); ++i) {
std::csub_match sub_match = results[i];
std::string sub_match_str = sub_match.str();
std::cout << i << ": " << sub_match_str << 'n';
}
}
生成如下输出:
0: # ff0000
1: ff
2: 00
03:00