C ++将子字符串解析为整数

C++ parse sub-string to integer

我需要一个 strtol 函数,它允许我指定解析字符串的范围。例如

char * number = "123456789";
std::cout << my_strtol(number, 1, 3);

应该打印“234”。


使用一些指针算法我可以非常接近:

int32_t my_strtol(const char* str, int from_char, int to_char, int base = 10)
{
  char *end;
  auto res = strtol(str + from_char, &end, base);
  auto extra_digits = end - str - (to_char + 1);
  if(extra_digits > 0) res /= pow(10, extra_digits); 
  return res;
}

然而,如果字符串大于 LONG_MAX(无论该部分的值如何),它就会失败。例如输入 "1234567890123456789" 调用 str_to_l(number, 1, 3) 会失败并且 return 0。此外它使用不必要的 pow – 性能是至关重要的。

编辑: 我想避免构造新的字符串或字符串流,因为我将从同一个缓冲区中提取多个整数,更重要的是我会 从字面上看 执行数以万计的此类调用。


对于那些对建议解决方案的(随意)分析结果感兴趣的人:

//put temp null character at end
int32_t my_strtol1(char* str, int from_char, int to_char, int base = 10)
{
    char tmp = str[to_char];
    str[to_char] = '[=12=]';
    auto res = strtol(str + from_char, nullptr, base);
    str[to_char] = tmp;
    return res;
}

//use substr()
int32_t my_strtol2(const std::string& str,
    const std::string::size_type from_char,
    const std::string::size_type to_char,
    int base = 10) {
    return std::stol(str.substr(from_char, to_char - from_char + 1));
}

//using boost
int32_t my_strtol3(char* str, int from_char, int to_char) {
    return boost::lexical_cast<int>(str + from_char, to_char - from_char + 1);
}

//parse characters one by one
int32_t my_strtol4(const char* str, int from_char, int to_char)
{
    int32_t res = 0;
    for (int i = from_char; i < to_char; i++)
    {
        char ch = str[i];
        ch -= '0';
        if (ch > 10 || ch < 0) return 0;
        res *= 10;
        res += ch;
    }
    return res;
}

我机器上的输出(由 clock_t 测量)是:

Manipulating null character with 100000 iterations took 0.114s
Using substr() with 100000 iterations took 0.62s
Using boost::lexical_cast<T>() with 100000 iterations took 0.231s
Parsing character one by one with 100000 iterations took 0.083s

因此,如果您不需要超级便携性(例如支持泰文、中文和阿拉伯数字):

int32_t my_strtol(const char* str, int from_char, int to_char, int base = 10)
{
   int32_t res = 0; 
   for(int i = from_char; i < to_char; i++)
   {
      char ch = str[i];
      if (ch > '9' && base > 10)
      {
         ch &= ~32;    /* Make it upper case */
         ch -= 'A' + 10;
      }
      else 
      {
          ch -= '0';
      }
      if (ch > base || ch < 0)   ... do some error handling ... 
      res *= base;
      res += ch;
   }
   return res;
}

如果你有 Boost,可以使用 boost::lexical_cast 作为单行代码完成,它有一个重载,需要一个 char 指针和长度作为参数。据我所知,这是经过优化(专门化)的,可以直接对输入字符串进行操作,不执行任何复制或内存分配,也不涉及任何流。

#include <iostream>
#include <boost/lexical_cast.hpp>

int
main()
{
  const auto text = "123456789";
  const auto number = boost::lexical_cast<int>(text + 1, 3);
  std::cout << number << '\n';
}

输出:

234

我知道我最初是从前一段时间对一个非常相似的问题的另一个答案中学到的,但我没能再次找到它,所以我会在这里复制它。