我的vector
包含strings
,其格式为text_number-number
例如: Example_45-3
我只想要第一个数字(示例中为45
),而我当前的代码只能使用其他内容:
std::vector<std::string> imgNumStrVec;
for(size_t i = 0; i < StrVec.size(); i++){
std::vector<std::string> seglist;
std::stringstream ss(StrVec[i]);
std::string seg, seg2;
while(std::getline(ss, seg, '_')) seglist.push_back(seg);
std::stringstream ss2(seglist[1]);
std::getline(ss2, seg2, '-');
imgNumStrVec.push_back(seg2);
}
是否有更简化和更简单的方法?如果是的话,他们是什么?
我纯粹是出于渴望学习如何在一天结束时更好地编码,上面的代码确实成功地提取了第一个数字,但它看起来很长并且很圆润。
答案 0 :(得分:19)
您还可以使用内置的find_first_of
和find_first_not_of
来查找第一个&#34;数字字符串&#34;在任何字符串中。
std::string first_numberstring(std::string const & str)
{
std::size_t const n = str.find_first_of("0123456789");
if (n != std::string::npos)
{
std::size_t const m = str.find_first_not_of("0123456789", n);
return str.substr(n, m != std::string::npos ? m-n : m);
}
return std::string();
}
答案 1 :(得分:18)
这应该比Ashot Khachatryan的解决方案更有效。请注意使用'_'
和'-'
代替"_"
和"-"
。此外,搜索'-'
的起始位置。
inline std::string mid_num_str(const std::string& s) {
std::string::size_type p = s.find('_');
std::string::size_type pp = s.find('-', p + 2);
return s.substr(p + 1, pp - p - 1);
}
如果您需要一个数字而不是字符串,就像Alexandr Lapenkov的解决方案所做的那样,您可能还想尝试以下方法:
inline long mid_num(const std::string& s) {
return std::strtol(&s[s.find('_') + 1], nullptr, 10);
}
答案 2 :(得分:13)
检查出来
std::string ex = "Example_45-3";
int num;
sscanf( ex.c_str(), "%*[^_]_%d", &num );
答案 3 :(得分:12)
我可以想到两种方法:
答案 4 :(得分:11)
我尝试更新此答案以在我的计算机上使用C ++ 11,但因为我的g ++编译器没有完整的<regex>
支持而失败...所以我一直没有被std::regex_error
{{1 ()&#34;缺少括号&#34;)任何带括号字符类code=4
的正则表达式的例外。
显然已为g++ version 4.9.x and on Jun 26, 2015实施并发布了对C ++ 11 std::regex("[0-9]")
的完全支持。提示问题#1和#2以确定需要为4.9.x的编译器版本。
这是应该有效的C ++ 11代码,但我无法测试它:
<regex>
适用于许多字符串的最小实现示例(不仅仅是表单的字符串&#34; text_45-text&#34;:
#include <iostream>
#include <string>
#include <regex>
using std::cout;
using std::endl;
int main() {
std::string input = "Example_45-3";
std::string output = std::regex_replace(
input,
std::regex("[^0-9]*([0-9]+).*"),
std::string("\\1")
);
cout << input << endl;
cout << output << endl;
}
控制台输出:
#include <iostream>
#include <string>
using namespace std;
#include <boost/regex.hpp>
int main() {
string input = "Example_45-3";
string output = boost::regex_replace(
input,
boost::regex("[^0-9]*([0-9]+).*"),
string("\\1")
);
cout << input << endl;
cout << output << endl;
}
可以使用的其他示例字符串:
对于这个例子,我在Linux上使用g ++ Example_45-3
45
和#include <boost/regex.hpp>
。您也可以使用C ++ 11x正则表达式。
如果你有更好的正则表达式,请随意编辑我的解决方案。
评论:
如果没有性能限制,使用正则表达式是理想的做法,因为你没有重新发明轮子(通过编写一堆字符串解析代码,需要时间来编写/测试完全)。
此外,如果/当您的字符串变得更复杂或具有更多变化的模式时,正则表达式可以轻松地适应复杂性。 (问题的示例模式很容易。但是,当一行正则表达式执行相同操作时,通常情况下更复杂的模式需要10-100行代码。)
答案 5 :(得分:9)
std::string s = "Example_45-3";
int p1 = s.find("_");
int p2 = s.find("-");
std::string number = s.substr(p1 + 1, p2 - p1 - 1)
答案 6 :(得分:8)
在C ++ 11及更高版本中执行此操作的“最佳”方法可能是使用regular expressions,当经常重复测试时,它会结合高表现力和高性能。
以下代码演示了基础知识。您应该#include <regex>
才能使用它。
// The example inputs
std::vector<std::string> inputs {
"Example_0-0", "Example_0-1", "Example_0-2", "Example_0-3", "Example_0-4",
"Example_1-0", "Example_1-1", "Example_1-2", "Example_1-3", "Example_1-4"
};
// The regular expression. A lot of the cost is incurred when building the
// std::regex object, but when it's reused a lot that cost is amortised.
std::regex imgNumRegex { "^[^_]+_([[:digit:]]+)-([[:digit:]]+)$" };
for (const auto &input: inputs){
// This wil contain the match results. Parts of the regular expression
// enclosed in parentheses will be stored here, so in this case: both numbers
std::smatch matchResults;
if (!std::regex_match(input, matchResults, imgNumRegex)) {
// Handle failure to match
abort();
}
// Note that the first match is in str(1). str(0) contains the whole string
std::string theFirstNumber = matchResults.str(1);
std::string theSecondNumber = matchResults.str(2);
std::cout << "The input had numbers " << theFirstNumber;
std::cout << " and " << theSecondNumber << std::endl;
}
答案 7 :(得分:0)
使用@Pixelchemist的答案,例如std::stoul
:
bool getFirstNumber(std::string const & a_str, unsigned long & a_outVal)
{
auto pos = a_str.find_first_of("0123456789");
try
{
if (std::string::npos != pos)
{
a_outVal = std::stoul(a_str.substr(pos));
return true;
}
}
catch (...)
{
// handle conversion failure
// ...
}
return false;
}