C ++字符串解析的想法 [英] C++ string parsing ideas

查看:90
本文介绍了C ++字符串解析的想法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有另一个程序的输出,更多的是人类可读性比机器可读,但仍然要解析它。这不是太复杂了。



然而,我想知道什么是最好的方法来做这个在C + +。这更像是一个一般做法的问题。



我看了Boost.Spirit,甚至得到了一点工作。那件事是疯了!如果 I 正在设计我正在阅读的语言,它可能是正确的工作工具。但是,因为它是,由于其极端的编译时间,当我做错了,从g ++的几页错误,这只是不是我需要的。 (我也不需要运行时的性能。)



考虑使用C ++运算符<<,但这似乎没有价值。如果我的文件有约翰有5个小部件,其他玛丽在459 Ramsy街工作线如何甚至可以确保我有一行在我的程序的第一类型,而不是第二类型?我必须读整个行,然后使用像 string :: find string :: substr 我猜。



这会留下 sscanf

  if(sscanf(str,%s has%d widgets,chararr,& intvar)== 2)
//然后我知道我匹配的foo has bar类型的字符串,
//和我现在有参数太多



所以我只是想知道如果我错过了一些东西,或者如果C ++真的没有很多内置的替代。

解决方案

sscanf 确实听起来非常适合您的要求:




  • 您可能会进行一些冗余的解析,但您没有性能要求禁止

  • 不同的输入字词,并允许将非字符串值直接解析为类型化的变量,使不同的输入格式更容易理解。



问题是它很容易出错,如果你有很多不断变化的解析短语,那么测试工作和风险可能令人担忧。保持 sscanf 的精神,但对类型安全使用 istream

  #include< iostream> 
#include< sstream>

// Str捕获一个字符串文字,并从istream消耗相同...
//(对于非文字,最好有`std :: string`成员来保证生命周期)
class Str
{
public:
Str(const char * p):p_(p){}
const char * c_str()const {return p_ ; }
private:
const char * p_;
};

bool operator!=(const Str& lhs,const Str& rhs)
{
return strcmp(lhs.c_str(),rhs.c_str ;
}

std :: istream& operator>>>(std :: istream& is,const Str& str)
{
std :: string s;
if(is>> s)
if(s.c_str()!= str)
is.setstate(std :: ios_base :: failbit);
return is;
}

//示例用法...

int main()
{
std :: stringstream是4 cats);
int num_dogs,num_cats;

if(is>> Str(Mary)>> Str(has)>> num_dogs> Str(dogs))
{
std :: cout<< num_dogs<< dogs\\\
;
}
else if(is.clear(),is.seekg(0),//resetthe stream ...
(is> )>>>>>>>>> Str(has)>>> num_cats> Str(cats num_cats<< cats\\\
;
}
}


I have the output of another program that was more intended to be human readable than machine readable, but yet am going to parse it anyway. It's nothing too complex.

Yet, I'm wondering what the best way to do this in C++ is. This is more of a 'general practice' type of question.

I looked into Boost.Spirit, and even got it working a bit. That thing is crazy! If I was designing the language that I was reading, it might be the right tool for the job. But as it is, given its extreme compile-times, the several pages of errors from g++ when I do anything wrong, it's just not what I need. (I don't have much need for run-time performance either.)

Thinking about using C++ operator <<, but that seems worthless. If my file has lines like "John has 5 widgets", and others "Mary works at 459 Ramsy street" how can I even make sure I have a line of the first type in my program, and not the second type? I have to read the whole line and then use things like string::find and string::substr I guess.

And that leaves sscanf. It would handle the above cases beautifully

if( sscanf( str, "%s has %d widgets", chararr, & intvar ) == 2 )
      // then I know I matched "foo has bar" type of string, 
      // and I now have the parameters too

So I'm just wondering if I'm missing something or if C++ really doesn't have much built-in alternative.

解决方案

sscanf does indeed sound like a pretty good fit for your requirements:

  • you may do some redundant parsing, but you don't have performance requirements prohibiting that
  • it localises the requirements on the different input words and allows parsing of non-string values directly into typed variables, making the different input formats easy to understand

A potential problem is that it's error prone, and if you have lots of oft-changing parsing phrases then the testing effort and risk can be worrying. Keeping the spirit of sscanf but using istream for type safety:

#include <iostream>
#include <sstream>

// Str captures a string literal and consumes the same from an istream...
// (for non-literals, better to have `std::string` member to guarantee lifetime)
class Str
{
  public:
    Str(const char* p) : p_(p) { }
    const char* c_str() const { return p_; }
  private:
    const char* p_;
};

bool operator!=(const Str& lhs, const Str& rhs)
{
    return strcmp(lhs.c_str(), rhs.c_str()) != 0;
}

std::istream& operator>>(std::istream& is, const Str& str)
{
    std::string s;
    if (is >> s)
        if (s.c_str() != str)
            is.setstate(std::ios_base::failbit);
    return is;
}

// sample usage...

int main()
{
    std::stringstream is("Mary has 4 cats");
    int num_dogs, num_cats;

    if (is >> Str("Mary") >> Str("has") >> num_dogs >> Str("dogs"))
    {
        std::cout << num_dogs << " dogs\n";
    }
    else if (is.clear(), is.seekg(0), // "reset" the stream...
             (is >> Str("Mary") >> Str("has") >> num_cats >> Str("cats")))
    {
        std::cout << num_cats << " cats\n";
    }
}

这篇关于C ++字符串解析的想法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆