C++ 忽略';E';使用sscanf读取双精度时

C++ 忽略';E';使用sscanf读取双精度时,c++,c,scanf,C++,C,Scanf,我有一些输入,例如“(50.1003781N,14.3925125E)”。这些是纬度和经度 我想用 sscanf(string,"(%lf%c, %lf%c)",&a,&b,&c,&d); 但是当%lf在数字后面看到E时,它会消耗它并以指数形式将其存储为数字。有没有办法禁用此功能?您可以尝试读取所有字符串,然后用另一个字符替换E首先使用 char *p; while((p = strchr(string, 'E')) != NULL) *p = 'W'; whi

我有一些输入,例如
“(50.1003781N,14.3925125E)”
。这些是纬度和经度

我想用

sscanf(string,"(%lf%c, %lf%c)",&a,&b,&c,&d);

但是当
%lf
在数字后面看到
E
时,它会消耗它并以指数形式将其存储为数字。有没有办法禁用此功能?

您可以尝试读取所有字符串,然后用另一个字符替换E

首先使用

char *p;
while((p = strchr(string, 'E')) != NULL) *p = 'W';
while((p = strchr(string, 'e')) != NULL) *p = 'W';

// scan it using your approach

sscanf(string,"(%lf%c, %lf%c)",&a,&b,&c,&d);

// get back the original characters (converted to uppercase).

if (b == 'W') b = 'E';    
if (d == 'W') d = 'E';
strchr()
在C头
中声明


注:这是一个C方法,不是C++方法。但是,通过使用
sscanf()
您实际上使用的是C方法。

我认为您需要手动解析,可能需要使用
strtod()
。这表明,当遇到尾随的
E
时,
strod()
表现正常(至少在Mac OS X 10.10.3和GCC 4.9.1上是如此,但可能无处不在)

基本上,你会跳过空格,检查一个
strod()
一个数字,检查
N
S
或小写版本,逗号,
strod()
一个数字,检查
W
E
,检查
可能在它前面允许空白

升级的代码,带有基于
strtod()
等的中等通用
strtolatlon()
函数。在函数中,例如
strtod()
需要“const cast”,它接受
const char*
输入,并通过
char**eptr
变量将指针返回到该字符串中

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CONST_CAST(type, value) ((type)(value))

extern int strtolatlon(const char *str, double *lat, double *lon, char **eptr);

int strtolatlon(const char *str, double *lat, double *lon, char **eptr)
{
    const char *s = str;
    char *end;
    while (isspace(*s))
        s++;
    if (*s != '(')
        goto error;
    *lat = strtod(++s, &end);
    if (s == end || *lat > 90.0 || *lat < 0.0)
        goto error;
    int c = toupper((unsigned char)*end++);
    if (c != 'N' && c != 'S')  // I18N
        goto error;
    if (c == 'S')
        *lat = -*lat;
    if (*end != ',')
        goto error;
    s = end + 1;
    *lon = strtod(s, &end);
    if (s == end || *lon > 180.0 || *lon < 0.0)
        goto error;
    c = toupper((unsigned char)*end++);
    if (c != 'W' && c != 'E')  // I18N
        goto error;
    if (c == 'E')
        *lon = -*lon;
    if (*end != ')')
        goto error;
    if (eptr != 0)
        *eptr = end + 1;
    return 0;

error:
    if (eptr != 0)
        *eptr = CONST_CAST(char *, str);
    errno = EINVAL;
    return -1;
}

int main(void)
{
    const char latlon1[] = "(50.1003781N, 14.3925125E)";
    const char latlon2[] = "   (50.1003781N, 14.3925125E) is the position!";
    char *eptr;
    double d;
    errno = 0;      // Necessary in general, but Probably not necessary at this point
    d = strtod(&latlon1[14], &eptr);
    if (eptr != &latlon1[14])
        printf("PASS: %10.7f (%s)\n", d, eptr);
    else
        printf("FAIL: %10.7f (%s) - %d: %s\n", d, eptr, errno, strerror(errno));

    printf("Converting <<%s>>\n", latlon2);
    double lat;
    double lon;
    int rc = strtolatlon(latlon2, &lat, &lon, &eptr);
    if (rc == 0)
        printf("Lat: %11.7f, Lon: %11.7f; trailing material: <<%s>>\n", lat, lon, eptr);
    else
        printf("Conversion failed\n");

    return 0;
}

请注意,在一度(10-7˚)小数点后7位的1个单位相当于地面上大约一厘米(沿子午线定向;沿纬度平行线的一度表示的距离当然随纬度而变化).

一个选项是将输入字符串分解为子字符串并从中扫描。您可以用占位符值替换
E
,然后将
b
d
更改为
E
,如果它有占位符。您可以移动,使所有经度都是W而不是E吗?不确定我是否理解您的问题,我将在后面阅读这些坐标,如果它的WI存储为负双精度,如果它的EIL存储为正数,如果你不确定我的问题,请放心。这主要是一个笑话。你可能无法假装东方经度不存在。谢谢,那C++是什么方法?这是C++项目的一部分,我不能想到任何其他的东西,然后尝试使用sSCANF来使用这个代码,使用<代码> w '/COD>可能不是最好的主意。如果我去西部怎么办?至少,你需要记录你是否将
E
E
更改为
W
,这样你就可以在使用
sscanf()
后撤消更改。您可能希望记录原始字符,以便将字符串恢复原状。当然,这种方法也意味着不能扫描包含纬度/经度的字符串文字。重点是更改字符以进行扫描,并记录足够的信息以便检索值(例如,如果更改e-W,则乘以-1)。有效坐标不会有明显的东坐标和西坐标。在扫描坐标(检查字符串只包含一对坐标,检查SCANSF()等)的点之前和之后,需要一个完整的错误检查。C++方法将使用STD::string类型(并且可能不将变量命名为“string”)。std::string支持多种操作来替换子字符串等。对于扫描/解析(而不是sscanf()),一种方法是将字符串提供给std::istringstream,并使用它来提取值。
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror latlong.c -o latlong
$ ./latlong
PASS: 14.3925125 (E))
$
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CONST_CAST(type, value) ((type)(value))

extern int strtolatlon(const char *str, double *lat, double *lon, char **eptr);

int strtolatlon(const char *str, double *lat, double *lon, char **eptr)
{
    const char *s = str;
    char *end;
    while (isspace(*s))
        s++;
    if (*s != '(')
        goto error;
    *lat = strtod(++s, &end);
    if (s == end || *lat > 90.0 || *lat < 0.0)
        goto error;
    int c = toupper((unsigned char)*end++);
    if (c != 'N' && c != 'S')  // I18N
        goto error;
    if (c == 'S')
        *lat = -*lat;
    if (*end != ',')
        goto error;
    s = end + 1;
    *lon = strtod(s, &end);
    if (s == end || *lon > 180.0 || *lon < 0.0)
        goto error;
    c = toupper((unsigned char)*end++);
    if (c != 'W' && c != 'E')  // I18N
        goto error;
    if (c == 'E')
        *lon = -*lon;
    if (*end != ')')
        goto error;
    if (eptr != 0)
        *eptr = end + 1;
    return 0;

error:
    if (eptr != 0)
        *eptr = CONST_CAST(char *, str);
    errno = EINVAL;
    return -1;
}

int main(void)
{
    const char latlon1[] = "(50.1003781N, 14.3925125E)";
    const char latlon2[] = "   (50.1003781N, 14.3925125E) is the position!";
    char *eptr;
    double d;
    errno = 0;      // Necessary in general, but Probably not necessary at this point
    d = strtod(&latlon1[14], &eptr);
    if (eptr != &latlon1[14])
        printf("PASS: %10.7f (%s)\n", d, eptr);
    else
        printf("FAIL: %10.7f (%s) - %d: %s\n", d, eptr, errno, strerror(errno));

    printf("Converting <<%s>>\n", latlon2);
    double lat;
    double lon;
    int rc = strtolatlon(latlon2, &lat, &lon, &eptr);
    if (rc == 0)
        printf("Lat: %11.7f, Lon: %11.7f; trailing material: <<%s>>\n", lat, lon, eptr);
    else
        printf("Conversion failed\n");

    return 0;
}
PASS: 14.3925125 (E))
Converting <<   (50.1003781N, 14.3925125E) is the position!>>
Lat:  50.1003781, Lon: -14.3925125; trailing material: << is the position!>>
int fmt_latlon(char *buffer, size_t buflen, double lat, double lon, int dp)
{
    assert(dp >= 0 && dp < 15);
    assert(lat >=  -90.0 && lat <=  90.0);
    assert(lon >= -180.0 && lon <= 180.0);
    assert(buffer != 0 && buflen != 0);
    char ns = 'N';
    if (lat < 0.0)
    {
        ns = 'S';
        lat = -lat;
    }
    char ew = 'W';
    if (lon < 0.0)
    {
        ew = 'E';
        lon = -lon;
    }
    int nbytes = snprintf(buffer, buflen, "(%.*f%c, %.*f%c)", dp, lat, ns, dp, lon, ew);
    if (nbytes < 0 || (size_t)nbytes >= buflen)
        return -1;
    return 0;
}