C++ 控制台:解析 METAR 数据

Posted

技术标签:

【中文标题】C++ 控制台:解析 METAR 数据【英文标题】:C++ Console : Parsing METAR data 【发布时间】:2018-08-10 09:46:47 【问题描述】:

我正在开发我的第一个 Web 应用程序(天气可视化),它需要在后端使用一些轻量级的 c++。我使用 wget 下载原始文本,使用 c++ 控制台解析数据,然后编写 html。到目前为止效果很好。

METAR 基本上是来自一个站的原始天气数据。 (时间、日期、条件、温度等)。我目前使用的是:

2018/08/10 08:09
KBAZ 100809Z AUTO 00000KT 10SM BKN012 26/23 A3002 RMK AO2 T02610233

我已经能够将每组数据存储到不同的变量中。我正在查看的问题是上面的“26/23”,即温度和露点,以摄氏度为单位。

到目前为止,我有一个名为 tempAndDewpoint 的字符串,其中存储了“26/23”...我正在使用 substr(0,2) 在一个名为 temperature 的新字符串中返回正确的温度。 (因为第一个数字是温度)。这很好用。

我的问题是,如果温度低于 10,比如 9,会发生什么?我不能再使用 substring(0,2),因为那样会返回“9/”作为当前温度。

我希望找到一些对我来说不太复杂的指导。我什至不确定如何命名这个问题,因为我不确定这个问题叫什么。肯定很常见吧?

【问题讨论】:

尝试根据分隔符将字符串拆分为子字符串。 【参考方案1】:

注意:METAR 中的负温度以 M 为前缀。因此这些是有效的温度组:5/M2 或 M8/M12(负露点实际上是结冰点)。所以我不会在这里使用自定义解析器:

struct TTD 
    short int t;
    short int td;

    bool parse(const char *tempAndDewpoint) 
        const char *next;
        t = parse_partial(tempAndDewpoint, &next);
        if (*next != '/') return false;
        td = parse_partial(next + 1, &next);
        return (*next == '\0');
    

private:
    static short int parse_partial(const char *beg, const char **next) 
        bool neg = false;
        short int val = 0;
        if (*beg == 'M') 
            neg = true;
            beg += 1;
        
        while (*beg >= '0' && *beg <= '9') 
            val = val * 10 + (*beg -  '0');
            beg += 1;
        
        *next = beg;
        if (neg) val = -val;
        return val;
    

;

【讨论】:

METAR 格式会改变吗?例如,“26/23”是流入我的程序的第 9 条数据。现在输入很容易,但是否有温度/露点不是第 9 个数据块的情况?如果是这样,我怎么知道它会是哪一个?我是 METAR 的新手 @David:METAR、SPECI 和 TAF 的本意是让人类直接可读,而不是对解析器友好。 Wikipedia page 为某些元素提供了指向更详细的archive 的链接,其中包含代码描述。很长时间我自己都没有解码 METAR,但我记得能见度和重要天气场的数量可能会有所不同,所以你不能指望临时组总是排在第 9 位... @David ... 我曾经为 METAR 写过一个解码器,但是由于语法不简单,所以使用 lex+yacc 来解析它。 感谢您的建议。因为这是一个雄心勃勃的项目,而且我是一名初级程序员,所以我最终使用了 weather.gov 网页并改为解析 HTML,因为它与 METAR 一样可靠。我将在几个月后返回此页面,因为我最终将要解析原始 METAR。感谢您的帮助!【参考方案2】:

简单的解决方案是根本不存储为字符串。将字符串拆分为两个独立的数字。如另一个答案中所述,您确实需要注意“M”是负数的前缀,但没有读取手动解析数字:

int parseNum(const std::string& str)

    size_t pos;
    int num;
    if (!str.empty() && str.front() == 'M')
    
        num = -std::stoi(str.substr(1), &pos);
        if (pos != str.size() - 1)
        
          throw std::invalid_argument("invalid input");
        
    
    else
    
        num = std::stoi(str, &pos);
        if (pos != str.size())
        
          throw std::invalid_argument("invalid input");
        
    
    return num;


size_t slash = tempAndDewpoint.find("/");
if (slash == std::string::npos)

  throw std::invalid_argument("invalid input");

int temp = parseNum(tempAndDewpoint.substr(0, slash));
int dew = parseNum(tempAndDewpoint.substr(slash + 1));

【讨论】:

以上是关于C++ 控制台:解析 METAR 数据的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Qt 集成到现有的 C++ 项目中

c++如何改变控制台文字颜色

Java端ACM输入解析器(高效)

c++中scanf和cout有啥区别

并行解析 C++

C++流对象