C++ c++;从流中提取双精度

C++ c++;从流中提取双精度,c++,iostream,C++,Iostream,我对学校的运动有一个有趣的问题。我得到了纬度和经度,我必须确保它的格式正确:\(\d+\.\d+[NS],\d\+.\d+[EW]\)。如您所见,我必须检查 有 char lBracket, rBracket, comma, NS, EW; int nLat, nLon; double lat, lon; istringstream iss ("(51.5N, 0.0E)"); iss >> fixed >> lBracket >> nLa

我对学校的运动有一个有趣的问题。我得到了纬度和经度,我必须确保它的格式正确:
\(\d+\.\d+[NS],\d\+.\d+[EW]\)
。如您所见,我必须检查

char    lBracket, rBracket, comma, NS, EW;
int     nLat, nLon;
double  lat, lon;

istringstream iss ("(51.5N, 0.0E)");

iss >> fixed >> lBracket >> nLat >> lat >> NS >> comma >> 
                   nLon >> lon >> EW >> rBracket;
lat += nLat;
lon += nLon;
>lon
提取
“.0E”
部分(这是一个有效的双精度),但我需要将其提取到EW

我提出的唯一解决方案是用其他字母替换
E
,这可能会起作用,但不是很好的代码

这个问题还有其他更优雅的解决方案吗


PS:您猜对了,不允许使用正则表达式:D

您实际上看到的是一个解析问题<代码>运算符>>(istream&,string&)是一个非常简单的解析器,只对空白进行标记

如果您的格式规范足够严格,您应该拒绝
(51.5N,0.0E)
(逗号前的额外空格),那么就不要提取逗号。相反,在提取之后,您应该检查
nLat
是否包含尾随逗号并将其删除。您不再需要逗号


如果必须在任何位置支持可选空格,则可以通过在逗号前后插入额外空格(无条件)来帮助预处理字符串。如果已经有一个空间,那么现在将有两个。这没有问题,因为跳过空格将跳过任何数量。

您的问题不是您所想的
.0E
不是有效的浮点数字 甚至在科学记数法中。它没有任何指数

发生的事情是流解析器被提交到解释中 当
.0E
到达
E
时,作为一个科学的浮点数字,然后 找不到指数;认为其解释是伪造的;将0分配给 目标加倍并在
iss
中设置
failbit
,因此不再从 流是可能的。您可以通过将
0.0E
更改为
1.1E
和 在尝试提取
lon之后立即测试
iss.fail()
仍然发现
lon
设置为0,而不是0.1,并且
iss.fail()==true

我认为在上下文中没有办法避免这一点
w.fE
w
=整个部分,
f
=小数部分) 如果试图使用
>
w.f
或仅将
.f
提取到浮点变量中。 在这种情况下,您已经超出了格式化
>
提取的舒适区 而且还需要变得更加灵活。事实上,这种需要并不仅仅来自于
w.fE
角盒,给定模式
\(\d+\.\d+[NS],\d\+.\d+[EW]\)
你告诉我们参考资料必须满足我们的要求。
\d+\.\d+[NS]
部分也很重要 对
>double>>char
>>[unsigned | int]>>double>>char
进行精确计算: 整数或浮点提取器将使用前导的
+
-
而浮点提取器也不会坚持使用 小数点或前后的非零数字计数

解析映射引用的繁琐(没有正则表达式的帮助)会 提示我为它们创建一个
map\u ref
类,以便您可以尝试提取
map\u ref
来自输入流(可能也来自字符串);可以询问
map\u ref
它是好的还是坏的(例如,在尝试提取之后),并且可以插入 格式化的
映射到输出流中

以下是此类课程的示意图:

#include <ostream>
#include <istream>
#include <iomanip>
#include <utility>
#include <limits>

struct map_ref
{
    map_ref() = default;
    map_ref(char NS, double lat, char EW, double lon)
    :   _NS(NS == 'N' || NS == 'S' ? NS : '?'),
        _EW(EW == 'E' || EW == 'W' ? EW : '?'),
        _lat(lat >= 0.0 && lat <= 90.0 ? lat : -1),
        _lon(lon >= 0.0 && lon <= 180.0 ? lon : -1),
        _good(_NS != '?' && _EW != '?' && _lat != -1 && _lon != -1){}

    // Todo: string ctor

    std::pair<char,double> latitude() const {
        return std::make_pair(_NS,_lat);
    }

    std::pair<char,double> longitude() const {
        return std::make_pair(_EW,_lon);
    }

    // Todo: setters, getters, equality etc.

    bool good() const {
        return _good;
    }

    bool read(std::istream & in);

    std::ostream & write(std::ostream & out, std::size_t precision = 4) const {
        return out << std::fixed << std::setprecision(precision) << 
            '(' << _lat << _NS << ", " << _lon << _EW << ')';
    }

    void clear() {
        *this = map_ref();
    }

private:
    double 
    read_fixed_point(std::istream & in, char & dest, std::string const & delims);
    char _NS = '?';
    char _EW = '?';
    double _lat = -1;
    double _lon = -1;
    bool _good = false;
};

double 
map_ref::read_fixed_point(
    std::istream & in, char & dest, std::string const & delims)
{
    std::string s;
    unsigned whole_digs = 0, frac_digs = 0;
    while(in >> dest && 
            dest != '.' && delims.find(dest) == std::string::npos)
    {
        whole_digs += std::isdigit(dest) != 0;
        s += dest;
    }
    if (dest != '.') {
        return -1;
    }
    s += dest;
    while(in >> dest && delims.find(dest) == std::string::npos)
    {
        frac_digs += std::isdigit(dest) != 0;
        s += dest;
    }
    if (whole_digs == 0 || frac_digs == 0 ||
        whole_digs + frac_digs > std::numeric_limits<double>::digits10 ||
        s.length() != 1 + whole_digs + frac_digs) {
            return -1;
    }
    return std::stod(s);
}


bool map_ref::read(std::istream & in)
{
    char lparen = 0;
    clear();
    in >> std::noskipws >> lparen;
    if (lparen != '(') {
        return _good = false;
    }
    _lat = read_fixed_point(in,_NS,"NS");
    if (_lat < 0.0 || _lat > 90.0) {
        return _good = false;
    }
    char comma = 0;
    in >> comma;
    if (comma != ',') {
        return _good = false;
    }
    while (std::isspace(in.peek())) {
        _EW = in.get();
    }
    _lon = read_fixed_point(in,_EW,"EW");
    if (_lon < 0.0 || _lon > 180.0) {
        return _good = false;
    }
    char rparen = 0;
    in >> rparen;
    return _good = rparen == ')';
}

std::istream & operator>>(std::istream & in, map_ref & mr)
{
    mr.read(in);
    return in;
}

std::ostream & operator<<(std::ostream & out, map_ref const & mr)
{
    return mr.write(out);
}
用于指定纬度和经度的精度 按照或在输出流中表示 接受默认的
4
。如果将其设置为0,则将丢失所有小数位 在输出上,所以不要这样做


该类带有全局运算符的重载
>
,您可以在输入字符串中将
E
替换为
X
(例如),运行代码后,可以在
EW
变量中将
X
替换为
E

char    lBracket, rBracket, comma, NS, EW;
int     nLat, nLon;
double  lat, lon;

std::string inputString = "(51.5N, 0.0E)";
size_t e_pos = inputString.find( 'E' );
if ( e_pos != std::string::npos ) {
    inputString.replace( e_pos, e_pos + 1, 'X' );
}
istringstream iss ( inputString );

iss >> fixed >> lBracket >> nLat >> lat >> NS >> comma >> 
                   nLon >> lon >> EW >> rBracket;

if ( EW == 'X' ) {
    EW = 'E';
}

lat += nLat;
lon += nLon;
更新:对不起,没有看到您的评论

我提出的唯一解决方案是用其他字母替换E,这可能会起作用,但不是很好的代码


如果你愿意,我将删除一个答案,这是典型的数学方法:如果你已经有了X的解,就足以把你的实际问题Y变成X。不要删除它。这是一个有效的答案,虽然不是我想要的答案,但它仍然对某些人有用:)你如何处理7位数的分数,并区分50.0000123和50.123?这段代码需要认真的工作来管理这些细节。顺便提一下,当用户键入50.123时,代码返回62.3。另请参见@JonathanLeffler I stand correct。答案出奇地错误。我希望更新不会发生。
#include <iostream>
#include <sstream>

static unsigned tests = 0, pass = 0, fail = 0;

static void expect_good(char NS, double lat, char EW, double lon )
{
    std::cout << "Testing (" << ++tests << ") " 
        << NS << ',' << lat << ',' << EW << ',' << lon << '\n';
    map_ref mr(NS,lat,EW,lon);
    if (!mr.good()) {
        std::cerr << "Failed (" << tests << "): Is good, got bad\n";
        ++fail;
    } else {
        ++pass;
        std::cout << "Passed (" << tests << "): Is good. Got \"" << mr << "\"\n";  
    }
}

static void expect_bad(char NS, double lat, char EW, double lon )
{
    std::cout << "Testing (" << ++tests << ") " 
        << NS << ',' << lat << ',' << EW << ',' << lon << '\n';
    map_ref mr(NS,lat,EW,lon);
    if (mr.good()) {
        std::cerr << "Failed (" << tests << "): Is bad, got good\n";
        ++fail;
    } else {
        ++pass;
        std::cout << "Passed (" << tests << "): Is bad, got bad\n";  
    }
}

static void expect_good(std::string const & s)
{
    std::cout << "Testing (" << ++tests << ") \"" << s << "\"\n";
    std::istringstream iss(s);
    map_ref mr;
    iss >> mr;
    if (!mr.good()) {
        std::cerr << "Failed (" << tests << "): Is good, got bad\n";
        ++fail;
    } else {
        ++pass;
        std::cout << "Passed (" << tests << "): Is good. Got \"" << mr << "\"\n";  
    }
}

static void expect_bad(std::string const & s)
{
    std::cout << "Testing (" << ++tests << ") \"" << s << "\"\n";
    std::istringstream iss(s);
    map_ref mr;
    iss >> mr;
    if (mr.good()) {
        ++fail;
        std::cerr << "Failed (" << tests << "): Is bad, got good\n";
    } else {
        ++pass;
        std::cout << "Passed (" << tests << "): Is bad, got bad\n"; 
    }
}


int main()
{
    expect_bad('E',1.00,'S',1.00);
    expect_bad('N',-1.00,'W',1.00);
    expect_bad('N',90.00,'W',180.01);
    expect_bad('S',90.01,'W',180.00);
    expect_good('S',90.00,'E',180.00);
    expect_good('S',0.0,'E',0.0);
    expect_bad("");
    expect_bad("1.1N, 2.2W");
    expect_bad("(1.1N, 2.2W");
    expect_bad("1.1N, 2.2W)");
    expect_bad("[1.1N, 2.2W)");
    expect_bad("(1.1N, 2.2W(");
    expect_bad("(N)");
    expect_bad("(N, W)");
    expect_bad("(0N, 1W)");
    expect_bad("(1.0N, 2W)");
    expect_bad("(1.0N, .2W)");
    expect_bad("(.01N, 1.2E)");
    expect_bad("(1.N, 1.2W)");
    expect_bad("(N1.1, E1.2)");
    expect_bad("(1.0N, 1.2 W)");
    expect_bad("(1.0X, 1.2W)");
    expect_bad("(1.0N, 1.2Z)");
    expect_bad("(+1.0N, 1.2E)");
    expect_bad("(1.+0N, 1.2E)");
    expect_bad("(1.0N, -1.2E)");
    expect_bad("(1.0N, 1.-2E)");
    expect_bad("(1.1N, 2.3.4E)");
    expect_bad("(0.0NN, 0.0E)");
    expect_bad("(0.0N, 0.0EW)");
    expect_bad("(0.0 1N, 0.0E)");
    expect_bad("(0.01N, 0 2.0E)");
    expect_bad("(0 .01N, 2.0E)");
    expect_bad("(0.01N, 2. 0E)");
    expect_bad("(12.34567890123456N, 2.0E)");
    expect_good("(0.0N, 0.0E)");
    expect_good("(1.0N,1.2W)");
    expect_good("(01.0N,01.2W)");
    expect_good("(1.0N,  1.2W)");
    expect_good("(0.123456789N, 0.000000001E)");
    expect_good("(0.000000001S, 0.123456789W)");
    expect_good("(0.123456789N, 0.000000001W)");
    expect_good("(0.000000001S, 0.123456789E)");
    expect_good("(1.1N, 12.3456789012345E)");
    expect_bad("(0.1E, 0.1N)");
    expect_bad("(0.1W, 0.1S)");
    expect_bad("(0.1W, 0.1N)");
    expect_bad("(0.1E, 0.1S)");
    expect_good("(90.0N, 180.0E)");
    expect_good("(90.0S, 180.0W)");
    expect_good("(90.0N, 180.0W)");
    expect_good("(90.0S, 180.0E)");
    expect_bad("(90.000001N, 180.0E)");
    expect_bad("(90.000001S, 180.0W)");
    expect_bad("(90.0N, 180.000001W)");
    expect_bad("(90.0S, 180.000001E)");
    std::cout << "Tests: " << tests << std::endl;
    std::cout << "Passed: " << pass << std::endl;
    std::cout << "Failed: " << fail << std::endl;  
    return 0;
}
char    lBracket, rBracket, comma, NS, EW;
int     nLat, nLon;
double  lat, lon;

std::string inputString = "(51.5N, 0.0E)";
size_t e_pos = inputString.find( 'E' );
if ( e_pos != std::string::npos ) {
    inputString.replace( e_pos, e_pos + 1, 'X' );
}
istringstream iss ( inputString );

iss >> fixed >> lBracket >> nLat >> lat >> NS >> comma >> 
                   nLon >> lon >> EW >> rBracket;

if ( EW == 'X' ) {
    EW = 'E';
}

lat += nLat;
lon += nLon;