我正在使用正则表达式对字符串进行标记;这通常在g++-4.9
下有效,但在g++-5.3.1
下失败。
我有以下txt文件:
0001-SCAND ==> "Scandaroon" (from Philjumba)
0002-KINVIN ==> "King's Vineyard" (from Philjumba)
0003-HANNI ==> "Hannibal: Rome vs. Carthage" (from Philjumba)
0004-LOX ==> "Lords of Xidit" (from Philjumba)
我使用正则表达式,空格,引号对和括号对进行标记。例如,第一行应该如下标记:
0001-SCAND
==>
"Scandaroon"
(from Philjumba)
我写了以下std::regex
:
std::regex FPAT("(\\S+)|(\"[^\"]*\")|(\\([^\\)]+\\))";
我用以下字符串对字符串进行标记:
std::vector<std::string>
split( const std::string & input, const std::regex & regex ) {
std::sregex_token_iterator
first{input.begin(), input.end(), regex, 0},
last;
return {first, last};
}
返回匹配项。在g++-4.9
下,字符串会根据请求进行标记,但在g++-5.3.1
下,它会被标记为如下所示:
0001-SCAND
==>
"Scandaroon"
(from
Philjumba)
或第三行标记如下:
0003-HANNI
==>
"Hannibal:
Rome
vs.
Carthage"
(from
Philjumba)
问题是什么?
编辑:我调用的函数如下:
std::string line("0001-SCAND ==> \"Scandaroon\" (from Philjumba)");
auto elems = split( line, FPAT );
编辑:根据@xaxxon的反馈,我替换了一个向量返回迭代器,但它在g++-5.3
下仍无法正常工作。
std::vector<std::string>
split( const std::string & input, const std::regex & regex ) {
std::sregex_token_iterator
first{input.begin(), input.end(), regex, 0},
last;
std::vector< std::string > elems;
elems.reserve( std::distance(first,last) );
for ( auto it = first; it != last; ++ it ) {
//std::cout << (*it) << std::endl;
elems.push_back( *it );
}
return elems;
}
答案 0 :(得分:1)
正则表达式 Eager
因此对于正则表达式"Set|SetValue"
和文本"SetValue"
,正则表达式创建"Set"
。
您必须仔细选择订单:
std::regex FPAT(R"(("[^\"]*\")|(\([^\)])+\)|(\S+))");
\S+
最后是最后一次考虑。
另一种方法是不使用默认选项(参见http://en.cppreference.com/w/cpp/regex/syntax_option_type)
并使用std::::regex::extended
std::regex FPAT(R"((\S+)|("[^\"]*\")|(\([^\)])+\))", std::::regex::extended);
因此,g ++ - 5.3.1似乎修复了一个错误,因为g ++ - 4.9就此而言。
答案 1 :(得分:0)
你没有足够的帖子让我知道(你更新它显示你用左值调用它,所以这篇文章可能不属于,但我会留下它除非人们要我把它拿下来,但是如果你正在做我做的事情,你就忘记了迭代器是在源字符串中而且该字符串不再有效。
您可以从const
中移除input
,但是能够将rvalue放在那里非常方便,所以......
这就是我要做的事情,以避免这种情况 - 我将unique_ptr返回到看起来像结果的东西,但我隐藏了实际的源字符串,以便在我和#之前strsing不会消失39;完成后使用它。这可能是UB,但我认为它几乎会一直有效:
// Holds a regex match as well as the original source string so the matches remain valid as long as the
// caller holds on to this object - but it acts just like a std::smatch
struct MagicSmatch {
std::smatch match;
std::string data;
// constructor makes a copy of the string and associates
// the copy's lifetime with the iterators into the string (the smatch)
MagicSmatch(const std::string & data) : data(data)
{}
};
// this deleter knows about the hidden string and makes sure to delete it
// this cast is probably UB because std::smatch isn't a standard layout type
struct MagicSmatchDeleter {
void operator()(std::smatch * smatch) {
delete reinterpret_cast<MagicSmatch *>(smatch);
}
};
// the caller just thinks they're getting a smatch ptr.. but we know the secret
std::unique_ptr<std::smatch, MagicSmatchDeleter> regexer(const std::regex & regex, const std::string & source)
{
auto magic_smatch = new MagicSmatch(source);
std::regex_search(magic_smatch->data, magic_smatch->match, regex);
return std::unique_ptr<std::smatch, MagicSmatchDeleter>(reinterpret_cast<std::smatch *>(magic_smatch));
}
只要你将其称为auto results = regexer(....),那么它很容易使用,虽然results
是指针,而不是正确的smatch
,所以[]
语法不能很好地工作。