在C ++中将特定格式的数字转换为long / double

时间:2011-10-31 22:48:10

标签: c++ floating-point integer

我正在为编程语言编写一个解释器,我用C ++语言编写,坦白说,我很坦率。

我想要完成的是在std::string转换特定的浮动格式  到一个双(或其他)。我希望它完全独立于语言环境,并尽可能强大。

我有两个案例:

  • 整数:它们应该是0-9的连续数字,带或不带前导减号(不允许加号,允许前导零)
  • 浮点数:[整个部分]。[小数部分]有或没有前导减号且没有任何千位分隔符。可以省略整个部分或小数部分(例如.44.),但不能同时

我希望它能成为“C ++方式”。是否有一个函数可用于指定自定义数字格式(类似于PHP中的date)。

我将非常感谢所提供的任何指针或代码片段。谢谢!

3 个答案:

答案 0 :(得分:2)

我不知道iostream支持严格的输入格式化。

但是,你可以使用Boost Spirit:

使用RealPolicy的标准真实解析器

请参阅http://www.boost.org/doc/libs/1_47_0/libs/spirit/doc/html/spirit/qi/reference/numeric/real.html

这将允许您明确定义为指数,符号和任何(数千)分隔符接受的格式。这也是一种非常复杂的方法,但它非常快速且非常灵活(适用于非标准数字类型,IIRC)。

两阶段解析

您可以使用Spirit Qi规则指定确切的格式,只有符合您的要求时才将raw[]输入序列传递给标准数字解析器。

更多参与,但也更优化的方式,是使用精神词汇表来标记输入 - 有效地做同样但更有效。

中间地带

这里的中间地点是使用普通的(Posix | Perl | C ++ 11 | Boost)正则表达式来验证输入格式并将其传递给任何合适的转换(如Boost Lexical cast,或者只是std :: stringstream>> double等。)

示例在解析浮点数 的数字格式时显示Spirit Qi和正则表达式预匹配(语言 c ++ 0x 1

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/regex.hpp>

namespace qi=boost::spirit::qi;
namespace phx=boost::phoenix;

bool is_ok(const std::vector<char>& raw)
{
    static const boost::regex rx(R"(-?(\d*\.\d+|\d+\.\d*))");
    return boost::regex_match(raw.begin(), raw.end(), rx);
}

template <typename Input>
    void test(const Input& input)
{
    auto f(std::begin(input)), l(std::end(input));

    double parsed = 0;
    bool ok = qi::phrase_parse(f, l, 

       // this is the parser expression
       &(+qi::char_)[ qi::_pass = phx::bind(is_ok, qi::_1) ]
       >> qi::double_, 
       // end parser expression

       qi::space, parsed);

    std::cout << "DEBUG: '" << input << "'\t"  << std::boolalpha << ok << "\t" << parsed << std::endl;
}

int main()
{
    const std::string good[]  = { ".300", "300.", "-.4", "-4." };
    const std::string wrong[] = { "", ".", "1", "-1", "-1111", "3..", "+1", "+.1", "+1.", "+1.0", "+-2.", "-+2." };

    for (auto& input : good)
        test(input);

    for (auto& input : wrong)
        test(input);
}

<子> 1 使用c ++ 11 featurs:

  • 基于范围的
  • 正则表达式规范的原始字符串文字

答案 1 :(得分:0)

假设你的意思是字符串属于C语言环境:

template<class T>
std::string tostring(const T& input)
{
    stringstream ss;
    if (!(ss << input))
        throw std::runtime_error("cannot convert!");
    return ss.str();
}

template<class T>
void fromstring(const std::string& input, T& output)
{
    stringstream ss(input);
    if (!(ss >> output) || ss)
        throw std::runtime_error("cannot convert!");
}
//Passes output as parameter, in case it's not copiable.

int main() {

    float pi = 3.14159f;  //pi to string and back
    std::string strpi = tostring(pi);
    fromstring(strpi, pi);

    std::ifstream in("in.txt");  //copies a file through a string
    std::string file = tostring(in);
    std::ofstream out("out.txt");
    fromstring(file, out);

    return 0;
}

答案 2 :(得分:0)

  

整数:它们应该是0-9的连续数字,带或不带前导减号(不允许加号,允许前导零)

     

浮点数:[整个部分]。[小数部分]有或没有前导减号且没有任何千位分隔符。可以省略整个部分或小数部分(例如.4或4.),但不能同时使用

这些几乎不是“自定义格式”;它们可以通过stringstream完美地解析(或者,如果您使用BOOST,则lexical_cast)。

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

int main( ... ) {   
    std::string s = "-1.0";
    float f = 0;        
    if( std::stringstream(s) >> f ) {
        std::cout << f;
    }
    else {
        std::cout << "No good!";
    }

    return 0;
}