我有一个字符串的丑陋,它由几个URI组成。
:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/0_301_0.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02011.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02012.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02110000.svg
我想要做的是删除每次出现的字符:/.,
,这样我就可以拥有一个有效文件名的字符串。
我已经编写了这个简单的正则表达式来表达jus:[^(:/,.)]
根据{{3}},它似乎是正确的正则表达式。
然而,当我运行以下C ++代码时,我没有得到我期望的东西(只是字母数字字符和下划线),我只是回到序列中的第一个字母数字字符:S
。
我对std :: regex做错了什么,或者我的正则表达式是什么?
#include <iostream>
#include <regex>
#include <string>
static const std::string filenames {R"(:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/0_301_0.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02011.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02012.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02110000.svg)"};
static const std::regex filename_extractor("[^(:/,.)]");
int main() {
std::smatch filename_match;
if(std::regex_search(filenames, filename_match, filename_extractor))
{
std::cout << "Number of filenames: " << filename_match.size() << std::endl;
for(std::size_t i = 0; i < filename_match.size(); ++i)
{
std::cout << i << ": " << filename_match[i] << std::endl;
}
}
return 0;
}
答案 0 :(得分:3)
size()
的{{1}}会返回子表达式的数量+ 1(包含std::smatch
和(
,而您没有。)
您需要反复拨打std::regex_search
,或使用std::regex_iterator
。
此外,您的正则表达式实际上只搜索单个字符。
您需要使用)
来搜索最长的字符序列:+
。
以下是您的代码,其中包含cppreference.com的示例:
[^(:/,.)]+
但是,这也会返回中间的“目录”。
如果您使用正则表达式#include <iostream>
#include <iterator>
#include <regex>
#include <string>
static const std::string filenames {R"(:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/0_301_0.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02011.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02012.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02110000.svg)"};
static const std::regex filename_extractor("[^(:/,.)]+");
int main() {
auto files_begin = std::sregex_iterator(filenames.begin(), filenames.end(), filename_extractor);
for (auto i = files_begin; i != std::sregex_iterator(); ++i) {
std::string filename = i->str();
std::cout << filename << '\n';
}
return 0;
}
,则会得到我希望您拥有的结果:
[^(:,)]+
/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/0_301_0.svg
/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02011.svg
/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02012.svg
/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02110000.svg
仅搜索正则表达式的第一个出现,以及其中的任何子表达式。
例如,表达式std::regex_search
将匹配字符串ab([cd])([ef])
。
第一个匹配是部分xxabcfxxabdef
,其中abcf
与第一个子表达式c
匹配,[cd]
与第二个子表达式{{1}匹配}}
第二个匹配是e
部分(不是[ef]
!),其中abde
是第二个子表达式的匹配。
使用abdef
,搜索第一个匹配项,匹配器返回完整的第一个匹配项以及子表达式的匹配项。
如果要查找更多匹配项,则必须从字符串的其余部分(e
)开始搜索。
此外,正则表达式std::regex_search
仅匹配单个字符。 std::smatch::suffix()
会匹配[ef]
和[ef]+
s的最长序列。
因此,上面目标字符串的e
的第二个子表达式匹配将匹配f
,而不仅仅是ab([cd])([ef])
。
答案 1 :(得分:2)
我认为std::regex_replace
就是您所需要的:
#include <regex>
#include <string>
#include <iostream>
const std::string filenames {R"(:/MIL_STD/0_3.svg,:/SS/2525D/02011.svg)"};
const std::regex filename_extractor("[(:/,.)]");
int main()
{
std::string r;
std::regex_replace(std::back_inserter(r),
filenames.begin(), filenames.end(), filename_extractor, "");
std::cout << "before: " << filenames << '\n';
std::cout << " after: " << r << '\n';
}
但是我觉得正则表达式对于删除字符可能有点过分,你可以使用std::remove_copy_if更有效地做到这一点:
#include <string>
#include <iostream>
#include <algorithm>
const std::string filenames {R"(:/MIL_STD/0_3.svg,:/SS/2525D/02011.svg)"};
const std::string filename_extractor("(:/,.)");
int main()
{
std::string r;
std::remove_copy_if(filenames.begin(), filenames.end(),
std::back_inserter(r), [](char c)
{
return filename_extractor.find(c) != std::string::npos;
});
std::cout << "before: " << filenames << '\n';
std::cout << " after: " << r << '\n';
}