【问题标题】:Determining if a string is a double判断一个字符串是否为双精度
【发布时间】:2021-08-29 11:35:06
【问题描述】:

我想看看一个字符串是否包含一个 double 作为其唯一内容。换句话说,如果它可能是以下函数的输出:

string doubleToString(double num)
{
    stringstream s;
    s << num;
    return s.str();
}

【问题讨论】:

  • 如果需要,请查看我的答案:stackoverflow.com/a/39813237/4316802
  • 字符串永远不是双精度的。
  • 错误的用户名,除了最后的 '\n' 之外,是否允许在数字文本之前和之前有空格?

标签: c++ string double


【解决方案1】:

您想要strtod 函数。

bool isOnlyDouble(const char* str)
{
    char* endptr = 0;
    strtod(str, &endptr);

    if(*endptr != '\0' || endptr == str)
        return false;
    return true;
}

【讨论】:

  • If no conversion is performed, zero is returned and the value of nptr is stored in the location referenced by endptr。如果碰巧是 0,我似乎无法使用这种检测双打的方法
  • if (x) return false; [else] return true; 更好地表示为 `return !(x);
  • Chris:它更好地考虑了代码:删除了 冗余“返回”,关键字 truefalse 显然是任何逻辑测试的结果,如以及同样隐含在这种情况下的if 声明。所以,这证明它更简洁。我无法证明它本身更简单或更好——这取决于维护它的程序员。尽管如此,经过 28 年的编程,我可以向您保证,业界的期望和最佳实践是,程序员应该努力了解布尔值的基本性质并相应地简化代码。
  • 根据文档,strdot小数点是本地依赖的。所以这意味着该函数旨在从用户输入中解析十进制数,但不适合解析一些定义明确的格式,例如文件。想象一下,您使用点作为小数点,但在捷克语 Windows 上是逗号默认小数点而不是点。所以 strdot 将寻找逗号,它是美国格式的千位分隔符。您将改为解析非十进制且完全不同的数字。
  • @BoundaryImposition: return endptr != str &amp;&amp; *endptr == '\0'; 没有以牺牲复杂性为代价进行压缩——它被简化了。如果您比 Chris 的回答中的 if 声明更难以解决这个问题,那么您不应该进行专业编程。
【解决方案2】:

您可以使用 Boost lexical_cast 来检查字符串是否包含双精度。

#include <boost/lexical_cast.hpp> 
....
using boost::lexical_cast; 
using boost::bad_lexical_cast; 
....
template<typename T> bool isValid(const string& num) { 
   bool flag = true; 
   try { 
      T tmp = lexical_cast<T>(num); 
   } 
   catch (bad_lexical_cast &e) { 
      flag = false; 
   } 
   return flag; 
} 

int main(){
  // ....
 if (isValid<double>(str))
     cout << "valid double." << endl; 
 else 
     cout << "NOT a valid double." << endl;
  //....
}

【讨论】:

  • -1 表示滥用异常。异常不应用于控制流,仅用于处理异常情况。
  • @Chris:我有,但不足以采用 python 风格。即便如此,在一种语言中正常的做法在另一种语言中是非常糟糕的做法。另一个例子是当你应该使用列表推导时在 OCaml 中编写 C++ 代码。
  • @Ben Voigt :我认为该代码比 Chris 发布的 sn-p 代码完美且干净。 lexical_cast&lt;T&gt;(num); 失败时抛出异常。我想不出更好的选择。
  • @Chris:但实际上,它捕获了一个异常以将其转换为返回值,即代码异味。在python中找不到它。要么你有一种具有轻量级异常的语言,并使用它们来报告失败,要么有重量级异常,如 C++,其中返回码用于预期的失败。
  • @Prasoon Saurav:清洁剂怎么样?
【解决方案3】:

已经为您提供了 C 风格和 boost 替代方案,但采用您的 doubleToString 实施风格:

bool is_double(const std::string& s)
{
    std::istringstream iss(s);
    double d;
    return iss >> d >> std::ws && iss.eof();
}

在这里,您正在检查 iss &gt;&gt; d 返回 iss,如果流式传输成功,它将仅在布尔上下文中评估为 true。在eof() 之前只检查空格,确保没有尾随垃圾。

如果您也想考虑前导和尾随空白垃圾:

    return iss >> std::nowkipws >> d && iss.eof();

这可以概括为类似于boost的lexical_cast&lt;&gt;的布尔返回测试...

template <typename T>
bool is_ws(const std::string& s)
{
    std::istringstream iss(s);
    T x;
    return iss >> x >> std::ws && iss.eof();
}

template <typename T>
bool is(const std::string& s)
{
    std::istringstream iss(s);
    T x;
    return iss >> std::noskipws >> x && iss.eof();
}

...
if (is<double>("3.14E0")) ...
if (is<std::string>("hello world")) ...; // note: NOT a single string
                                         // as streaming tokenises at
                                         // whitespace by default...

您可以将模板专门用于您想要的任何特定于类型的行为,例如:

template <>
bool is<std::string>(const std::string& s)
{
    return true;
}

【讨论】:

  • is 不应该是iss 部分!(is &gt;&gt; c)
【解决方案4】:

或者直接使用流:

#include <string>
#include <sstream>
#include <iostream>

template<typename T>
bool isValid(std::string const& num)
{
    T  value;
    std::stringstream stream(num);
    stream >> value;

    // If the stream is already in the error state peak will not change it.
    // Otherwise stream should be good and there should be no more data
    // thus resulting in a peek returning an EOF
    return (stream) &&
           stream.peek() == std::char_traits<typename std::stringstream::char_type>::eof();
}

int main()
{
    isValid<double>("55");
}

【讨论】:

    【解决方案5】:

    我做了一个可能有帮助的函数? 它还会检查诸如 12.3.4 或 1,4 之类的拼写错误。

    // check if input string is decimal
    bool is_decimal_str(string input)
    {
        int decimal = 0;
        int index = 0;
        for (auto character : input)
        {
            if (character == '.')
            {
                decimal++;
            }
            else if ((character == '+' || character == '-') && index == 0);
            else if (!isdigit(character))
            {
                return false;
            }
    
            if (decimal > 1)
            {
                return false;
            }
    
            index++;
        }
        return true;
    }
    

       // check if input string is decimal
        bool is_decimal_str(string input)
        {
            int decimal = 0;
            for (int index = 0; index < input.size(); index++)
            {
                if (input[index] == '.')
                {
                    decimal++;
                }
                else if ((input[index] == '+' || input[index] == '-') && index == 0);
                else if (!isdigit(input[index]))
                {
                    return false;
                }
        
                if (decimal > 1)
                {
                    return false;
                }
            }
            return true;
        }
    

    【讨论】:

      【解决方案6】:

      由于没有其他人提到它:显而易见的解决方案是您想知道一个字符串是否具有给定的语法是使用正则表达式。我不确定这是否是这种情况下的最佳解决方案,因为合法双精度的正则表达式相当复杂(因此很容易出错)。而且您的规范有些含糊:您是要接受任何可以解析的字符串(例如,&gt;&gt;)作为合法的双精度,还是您的doubleToString 函数只能返回字符串?如果是前者,最简单的解决方案可能是将字符串转换为双精度,确保没有错误并且您已经使用了所有字符(Martin 的解决方案,除了在需要之前将其设为模板很愚蠢) .如果是后者,最简单的解决方案是使用您的函数将找到的双精度重新转换回字符串,然后比较两个字符串。 (只是为了明确区别:Martin 的函数将返回 true 用于诸如 "&amp;nbsp;&amp;nbsp;1.0""1E2"".00000000001""3.14159265358979323846264338327950288419716939937" 之类的内容,您的函数将永远不会生成。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-31
        • 1970-01-01
        • 2013-03-11
        • 2019-04-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多