从具有任意结构的 C++ 中的字符串中提取整数

Posted

技术标签:

【中文标题】从具有任意结构的 C++ 中的字符串中提取整数【英文标题】:Extracting integers from strings in C++ with arbitrary structure 【发布时间】:2014-04-22 23:37:40 【问题描述】:

这似乎是一个应该很容易搜索的问题,但那里的任何答案似乎都被一大堆问题所淹没.

我的问题是:从std::strings 中提取可能看起来像"abcd451efg""hel.lo42-world!""hide num134rs here?" 的整数的简单方法是什么?我看到我可以使用isDigit 自己手动解析字符串,但是我想知道atoistoi等是否有更标准的方式。

上面的输出将是 451、42 和 134。我们还可以假设字符串中只有一个整数(尽管一般的解决方案不会有坏处)。所以我们不必担心像"abc123def456"这样的字符串。

Java 有一个简单的解决方案,形式为

Integer.parseInt(str.replaceAll("[\\D]", ""));

C++ 有这么简单的东西吗?

【问题讨论】:

std::regex_replace 怎么样? 它只适用于 C++11,而且大多数支持 C++11 的编译器还不支持正则表达式部分。我认为只有 g++4.9 完全支持正则表达式。 【参考方案1】:

你可以使用 string::find_first_of("0123456789") 得到第一个数字的位置,然后string::find_last_of("0123456789") 得到最后一个数字的位置,最后在这两个位置定义的子字符串上使用atoi。我想不出任何更简单的东西(没有正则表达式)。

顺便说一句,这仅在字符串中有一个数字时才有效。

这是一个例子:

#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;

int main()

    string s = "testing;lasfkj358kdfj-?gt";
    size_t begin = s.find_first_of("0123456789");
    size_t end = s.find_last_of("0123456789");
    string num = s.substr(begin, end - begin + 1);
    int result = atoi(num.c_str());
    cout << result << endl;
 

如果您有超过 1 个数字,您可以将 string::find_first_ofstring::find_first_not_of 组合在一起,以获取字符串中每个数字的开头和结尾。

此代码是通用解决方案:

#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

int main()

    string s = "testing;lasfkj358kd46fj-?gt"; // 2 numbers, 358 and 46

    size_t begin = 0, end = 0; 

    while(end != std::string::npos)
    
        begin = s.find_first_of("0123456789", end);
        if(begin != std::string::npos) // we found one
        
            end = s.find_first_not_of("0123456789", begin);
            string num = s.substr(begin, end - begin);
            int number = atoi(num.c_str());
            cout << number << endl;
        
    

【讨论】:

【参考方案2】:

即使有尾随非数字,atoi 也可以从字符串中提取数字

int getnum(const char* str)

    for(; *str != '\0'; ++str)
    
        if(*str >= '0' && *str <= '9')
            return atoi(str);
    
    return YOURFAILURENUMBER;

【讨论】:

【参考方案3】:

这是一种方法

#include <algorithm>
#include <iostream>
#include <locale>
#include <string>

int main(int, char* argv[])

  std::string input(argv[1]);

  input.erase(
    std::remove_if(input.begin(), input.end(), 
      [](char c)  return !isdigit(c, std::locale()); ),
    input.end()
  );

  std::cout << std::stoll(input) << '\n';

您还可以使用&lt;functional&gt; 库来创建谓词

auto notdigit = not1(
  std::function<bool(char)>(
    bind(std::isdigit<char>, std::placeholders::_1, std::locale())
  )
);

input.erase(
  std::remove_if(input.begin(), input.end(), notdigit),
  input.end()
);

值得指出的是,到目前为止,其他两个答案对数字检查进行了硬编码,使用 locale 版本的 isdigit 保证您的程序将根据当前的全球语言环境识别数字。

【讨论】:

这肯定是提取一个子字符串的最优雅的方法,如果字符串有多个数字,你能做这样紧凑的事情吗? 一种方法是使用std::replace_if 将字母字符与空格交换出来,然后使用生成的字符串初始化std::istringstream

以上是关于从具有任意结构的 C++ 中的字符串中提取整数的主要内容,如果未能解决你的问题,请参考以下文章

从字符串 C++ 中提取某些整数

C++ - 从整数数组中插入和提取字符

c++ 怎样提取一个字符串中的连续数字并放到另一个数组中保存? 急!

C++:从具有固定格式的字符串中挑选部分/数据

从字符串C++中取出整数[重复]

JAVA中如何从字符串中提取一个整数