我发现一直使用的 strtod 方法存在问题。
首先它不理解非点小数点分隔符,所以我不得不使用这个:

std::replace(sSource.begin(), sSource.end(), getDecimalSeparator(), '.');

但不,我发现了另一个问题,但还没有找到解决方法。如果值为负且千位分隔符是一个点(“.”),则 strtod 返回 0 并且 _EndPtr 指向字符串的开头:
// PRECONDITIONS:
//  * digit grouping symbol (thousands separator) = "."
//  * decimal symbol                              = ","
//  * digital grouping                            = "123.456.789"
//  * negative sign symbol                        = "-"
//  * negative number format                      = "- 1,1"
//  * OS WinXP SP2
//  * the rest doesn't matter

double parse(const char* cszValue, char** szStop)
{
    // NOTE: error handling code has been removed to simplify the sample
    return strtod(sSource.c_str(), szStop);
}

//...
char* szStop = NULL;
double dVal = 0.0;
dVal = parse("123.45",     &szStop); // works!

// All the next DON'T WORK!
dVal = parse("123,45",     &szStop); // dVal == 123.0 szStop == ",45"
dVal = parse("- 123.45",   &szStop); // dVal == 0.0   szStop == "- 123.45"
// the same for "- 123,45"
dVal = parse("1.123.45",   &szStop); // dVal == 1.123 szStop == ".45"
// the same for "1.123,45"
dVal = parse("1 123.45",   &szStop); // dVal == 1     szStop == " 123.45"
// the same for "1 123,45"
dVal = parse("- 1 123,45", &szStop); // dVal == 0     szStop == start of the string
// the same for "- 1 123.45", "- 1.123,45", "- 1.123.45"

有以下问题:
  • 我做错了什么? (回答)
  • 如果根据本地设置格式化小数点分隔符,为什么 strtod 会失败? (回答)
  • 即使我用点(“.”)替换当前的小数点分隔符并删除所有千位分隔符,如何解析负值?检测负号,将其删除,将值解析为正数并在此之后反转负号?
  • 最佳答案

    关于不正确的结果,由于数字中的空格,我可以看到问题。根据文档 strtod() 此函数将删除前导空格并在找到数字中间的空格时停止读取并返回转换为 double 的值。例如,
    如果下面给出的 strtod 找到减号后的空格,并且减号 only 不是有效的数值,则返回 0.0。

    dVal = parse("- 123.45",   &szStop); // dVal == 0.0   szStop == "- 123.45"
    
    同样在下面的行的情况下,当它找到第二个小数时,它假定它结束了值,因为数值中不可能有两个小数。
    dVal = parse("1.123.45",   &szStop); // dVal == 1.123 szStop == ".45"
    
    在下面给出的行的情况下,它找到 1 之后的空间并停止进一步处理并将 1 作为解析的 double 返回。
    dVal = parse("1 123.45",   &szStop); // dVal == 1     szStop == " 123.45"
    
    下面的案例类似于我上面提到的第一个案例。
    dVal = parse("- 1 123,45", &szStop); // dVal == 0     szStop == start of the string
    
    我希望这有帮助。
    问候,
    阿热尔·伊克巴尔

    10-08 11:28