最直接的方式是用 std::isdigit 配合循环逐字符判断并拼接子串,注意传参需转 unsigned char;正则适合复杂模式但性能较差;stringstream 仅适用于分隔明确的规范输入;转换数字时优先用 std::from_chars 避免异常。

用 std::isdigit 配合循环逐字符判断最直接
多数场景下,你并不是要“提取所有数字连成一个整数”,而是想把字符串里连续的数字片段(比如 "abc123def45" 中的 "123" 和 "45")单独拿出来。这时候靠 std::isdigit 判断每个字符是否为数字,再手动拼接子串,是最可控、最不易出错的方式。
- 注意:
std::isdigit接收int,但必须传入unsigned char或 EOF,否则对负值(如 sign-extended char)行为未定义 —— 常见坑是直接传char变量,尤其在 Windows MSVC 下容易 crash 或误判 - 跳过前导空格、制表符等无关字符时,别只检查
' ',建议用std::isspace - 遇到非数字字符就结束当前数字片段,不要等到字符串结尾才处理最后一段
std::vector<std::string> extractNumbers(const std::string& s) {
std::vector<std::string> res;
std::string num;
for (char c : s) {
if (std::isdigit(static_cast<unsigned char>(c))) {
num += c;
} else {
if (!num.empty()) {
res.push_back(num);
num.clear();
}
}
}
if (!num.empty()) res.push_back(num); // 结尾还有数字
return res;
}
用正则表达式 std::regex 提取连续数字更简洁
如果你需要匹配带符号的整数(如 "-123")、小数("3.14"),或者想跳过某些上下文(比如只提取括号里的数字),std::regex 是更合适的工具。但要注意它在 C++11/14 中性能较差,且各标准库实现兼容性不一(libstdc++ 早期版本 regex 支持弱,MSVC 相对稳定)。
- 基础数字片段:正则用
R"(\d+)",注意双引号内不能写\d,必须用原始字符串字面量避免转义问题 - 匹配带符号整数:用
R"([-+]?\d+)",但会把单独的"+"或"-"也当作匹配 —— 需额外校验长度 ≥ 2 或检查后续是否真跟数字 - 避免重复构造
std::regex对象:如果在循环里反复调用,把它声明为static const更高效
std::vector<std::string> extractDigitsRegex(const std::string& s) {
static const std::regex re(R"(\d+)");
std::vector<std::string> res;
for (std::sregex_iterator it(s.begin(), s.end(), re), end; it != end; ++it) {
res.push_back(it->str());
}
return res;
}
用 std::stringstream 读数字只适用于“数字和分隔符混排”场景
std::stringstream 的 >> 操作符会跳过空白并尝试解析整数或浮点数,但它会“吃掉”输入流中第一个非数字字符(比如 "123abc" 会被读成 123,但后续 "abc" 就丢了),而且无法区分多个连续数字片段("123456" 总是当一个数读)。所以它只适合格式较规范的输入,例如日志行中固定位置嵌着数字,或空格/制表符明确分隔的字段。
- 读取失败后流状态会置
failbit,必须调用ss.clear()才能继续使用,否则后续读取全部失败 - 它不识别十六进制前缀(
"0x1A"),除非提前设置ss << std::hex - 遇到
"12a34"这种,只会读出12,然后停在'a',不会自动跳到后面的34
提取后要不要转成数值?小心溢出和异常
拿到数字字符串(如 "99999999999999999999")后,用 std::stoi/std::stol 转整数很常见,但这些函数在超出目标类型范围时抛 std::out_of_range 异常 —— 如果没捕获,程序直接终止。生产环境几乎从不直接用它们。
立即学习“C++免费学习笔记(深入)”;
- 更安全的做法:用
std::from_chars(C++17 起),它不抛异常、返回错误码,且不依赖 locale,速度也更快 - 若需支持大数,别硬转
long long,考虑保留为std::string或引入boost::multiprecision - 前导零问题:
"007"转整数变成7,如果业务需要保留原格式(比如版本号、编码),就别转


















