这是我在 MFC 应用程序中用于检查正则表达式匹配的代码:
int CDouserApp::FindMatches(std::vector<std::wstring>& output,
const std::wstring& input,
const std::wstring& pattern)
{
std::tr1::wregex rx(pattern);
std::tr1::wsmatch results;
output.clear();
if (!(std::tr1::regex_search(input, results, rx)))
{
return 0;
}
for (auto& r : results)
{
output.push_back(r.str());
}
return output.size();
}
void CDouserView::OnClickedSearch()
{
std::vector<std::wstring> ret;
std::wstring pattern(this->regexList.GetWindowTextLength() + 1, 0);
this->regexList.GetWindowText(&pattern[0], pattern.length());
std::wstring input(this->inputEdit.GetWindowTextLength() + 1, 0);
this->inputEdit.GetWindowText(&input[0], input.length());
CDouserApp::FindMatches(ret, input, pattern);
this->resultsList.DeleteAllItems();
std::wstringstream resultsStatus;
resultsStatus << ret.size() << " result(s)";
static_cast<CMainFrame*>(::AfxGetMainWnd())->GetStatusBar()
.SetWindowText(resultsStatus.str().c_str());
for (auto& match : ret)
{
this->resultsList.InsertItem(LVIF_TEXT, match.c_str());
}
}
如果我使用<h(.)>([^<]+)
and<h2>Egg prices</h2>
作为输入,即使它应该匹配“2”和“鸡蛋价格”,我也会得到 0 个结果。如果我Hello
用作正则表达式和Hello, world!
输入字符串,即使它应该与“Hello”匹配,我也会得到 0 个结果。
我什至尝试将输入和模式转换为 ASCII 并使用非宽std::regex
系列,但结果是相同的。迄今为止,唯一匹配任何内容的模式是.*
匹配整个字符串。
我知道 gcc 的正则表达式库已损坏,但我之前在 MSVC 中使用过 std::regex 并且没有遇到问题。如果可以避免的话,我想避免使用 boost::regex 或 pcre。
更新/编辑:此代码出于某种原因有效:
static void RegexTest(void)
{
std::tr1::wregex rx1(L"<h(.)>([^<]+)");
std::wstring input1(L"<h2>Egg prices</h2>");
std::tr1::wregex rx2(L"Hello");
std::wstring input2(L"Hello, world!");
std::tr1::wsmatch results;
if (!(std::tr1::regex_search(input1, results, rx1)))
{
::MessageBox(nullptr, L"No matches found", L"Done", MB_OK | MB_ICONASTERISK);
}
else
{
std::wstringstream s;
s << results.size() << " match(es) found:" << std::endl;
for (auto& m : results)
{
s << m.str() << std::endl;
}
::MessageBox(nullptr, s.str().c_str(), L"Done", MB_OK | MB_ICONINFORMATION);
}
if (!(std::tr1::regex_search(input2, results, rx2)))
{
::MessageBox(nullptr, L"No matches found", L"Done", MB_OK | MB_ICONASTERISK);
}
else
{
std::wstringstream s;
s << results.size() << " match(es) found:" << std::endl;
for (auto& m : results)
{
s << m.str();
}
::MessageBox(nullptr, s.str().c_str(), L"Done", MB_OK | MB_ICONINFORMATION);
}
}
最终更新(和解决方案):
经过大量分析和测试,我发现我必须从字符串中删除空终止符:
void CDouserView::OnClickedSearch()
{
std::vector<std::wstring> ret;
std::wstring pattern(this->regexList.GetWindowTextLength() + 1, 0);
this->regexList.GetWindowText(&pattern[0], pattern.length());
pattern.resize(pattern.length() - 1);
std::wstring input(this->inputEdit.GetWindowTextLength() + 1, 0);
this->inputEdit.GetWindowText(&input[0], input.length());
input.resize(input.length() - 1);
CDouserApp::FindMatches(ret, input, pattern);
this->resultsList.DeleteAllItems();
std::wstringstream resultsStatus;
resultsStatus << ret.size() << " result(s)";
static_cast<CMainFrame*>(::AfxGetMainWnd())->GetStatusBar()
.SetWindowText(resultsStatus.str().c_str());
for (auto& match : ret)
{
this->resultsList.InsertItem(LVIF_TEXT, match.c_str());
}
}
问题是 GetWindowText 在写入字符串的同时还添加了一个空终止符;STL 字符串认为这个空终止符实际上是数据的一部分。我不知道为什么 Dinkumware 在输入字符串末尾存在这个额外的 null 时会遇到这样的困难。我还没有用 Boost 测试它,看看它是否有同样的陷阱,但我怀疑它没有。