C++ 将十进制字符串拆分为两个整数

C++ Split decimal string into two integers

给定一个十进制值(秒及其分数)作为字符串,例如

std::string span = "ssss.nnnn"  // ssss is value in seconds, nnnn is fractional seconds

将其转换为 timeval 结构(val.ts_sec 和 val.ts_usec)或 timespec 结构(tv_sec 和 tv_nsec)的最佳方法是什么。

大多数答案都讨论了转换值或者不是 C++。有些答案变得非常复杂或设置 类 这对于这种用法来说实在是太多了。

显然,如果两个值由白色分隔,则可以使用 sscanf 或 istringstream space。但是,如果它们由“.”分隔,是否有一种简单的方法可以做到这一点?无需遍历字符缓冲区搜索“。”

我刚刚发现这是一个可能的答案。我也想找点别的东西。

Parse (split) a string in C++ using string delimiter (standard C++)

strtok allows you to pass in multiple chars as delimiters. I bet if you passed in ">=" your example string would be split correctly (even though the > and = are counted as individual delimiters).

EDIT if you don't want to use c_str() to convert from string to char*, you can use substr and find_first_of to tokenize.

string token, mystring("scott>=tiger");
while(token != mystring){
  token = mystring.substr(0,mystring.find_first_of(">="));
  mystring = mystring.substr(mystring.find_first_of(">=") + 1);
  printf("%s ",token.c_str());
}

更新:

@Wintermute 指出以下代码片段将无法运行,因为可能存在前导零。

string span;
int sec;
int usec;
timeval inTime;

sscanf(span.c_str(), "%d.%d", &sec, &usec);
inTime.tv_sec = sec;
inTime.tv_usec = usec;

编辑:正如 Borgleader 正确提到的那样,如果时间戳变得足够大(大于一百万,给予或接受),简单地读入双精度会导致精度损失。一个数值稳定的方法是

timeval v;
time_t seconds;
double fraction;

std::istringstream parser(span);

if(parser >> seconds >> std::noskipws >> fraction) {
  v.tv_sec  = seconds;
  v.tv_usec = static_cast<suseconds_t>(fraction * 1e6);
}

从现在开始,fraction 部分保证足够小,ieee-754 double 的尾数将覆盖逗号后超过 9 个十进制数字。一种可能的添加是

  v.tv_usec = static_cast<suseconds_t>(fraction * 1e6 + 0.5); // rounding to nearest instead of down

取决于您的用例。

您可以使用 strtok_s 根据分隔符拆分字符串。在你的情况下是“。”

#include <iostream>
#include <string>

int main()
{
    std::string span = "ssss.nnnn";
    char * span1 = (char *)span.c_str();
    char * pch = NULL;
    char * context;

    pch = strtok_s(span1, " .", &context);

    while (pch != NULL)
    {
        printf("%s\n", pch);
        pch = strtok_s(NULL, " .", &context);
    }

    return 0;
}

Output:

ssss

nnnn

如果您决定使用 string class 及其函数 如果数字始终为十进制,那么我建议采用以下解决方案:

  string span = "1234.123";
  span += "000000";
  size_t pos = span.find('.');

  struct timeval val;
  val.tv_sec = stol(span.substr(0,pos));
  val.tv_usec = stol(span.substr(pos+1,6));

如果string也可能得到不带点'.'的整数值字符然后使用

  string span = "1234";
  size_t pos = span.find('.');

  struct timeval val;
  val.tv_sec = stol( (pos!=string::npos)? span.substr(0,pos):span );
  val.tv_usec = (pos!=string::npos)? stol((span+"000000").substr(pos+1,6)):0;

这个解决方案也使用了一些c++11。