簡體   English   中英

C ++字符串解析(python樣式)

[英]C++ string parsing (python style)

我喜歡在python中我可以做的事情:

points = []
for line in open("data.txt"):
    a,b,c = map(float, line.split(','))
    points += [(a,b,c)]

基本上它正在讀取行列表,其中每行代表3D空間中的一個點,該點表示為由逗號分隔的三個數字

如何在沒有太多頭痛的情況下在C ++中完成這項工作?

性能不是很重要,這種解析只發生一次,因此簡單性更重要。

PS我知道這聽起來像是一個新手問題,但請相信我,我在D中編寫了一個詞法分析器(非常類似於C ++),它涉及通過char讀取一些文本字符並識別標記,
就是這樣,經過長時間的蟒蛇回到C ++之后,只是讓我不想浪費時間在這些事情上。

我會做這樣的事情:

ifstream f("data.txt");
string str;
while (getline(f, str)) {
    Point p;
    sscanf(str.c_str(), "%f, %f, %f\n", &p.x, &p.y, &p.z); 
    points.push_back(p);
}

x,y,z必須是浮點數。

並包括:

#include <iostream>
#include <fstream>

C ++字符串工具包庫(StrTk)具有以下解決方案:

#include <string>
#include <deque>
#include "strtk.hpp"

struct point { double x,y,z; }

int main()
{
   std::deque<point> points;
   point p;
   strtk::for_each_line("data.txt",
                        [&points,&p](const std::string& str)
                        {
                           strtk::parse(str,",",p.x,p.y,p.z);
                           points.push_back(p);
                        });
   return 0;
}

更多例子可以在這里找到

除了所有這些好的例子,在C ++中你通常會覆蓋你的點類型的operator >>來實現這樣的事情:

point p;
while (file >> p)
    points.push_back(p);

甚至:

copy(
    istream_iterator<point>(file),
    istream_iterator<point>(),
    back_inserter(points)
);

運算符的相關實現看起來非常像j_random_hacker的代碼。

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>     // For replace()

using namespace std;

struct Point {
    double a, b, c;
};

int main(int argc, char **argv) {
    vector<Point> points;

    ifstream f("data.txt");

    string str;
    while (getline(f, str)) {
        replace(str.begin(), str.end(), ',', ' ');
        istringstream iss(str);
        Point p;
        iss >> p.a >> p.b >> p.c;
        points.push_back(p);
    }

    // Do something with points...

    return 0;
}

這個答案是基於j_random_hacker之前的回答,並使用了Boost Spirit。

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <boost/spirit.hpp>

using namespace std;
using namespace boost;
using namespace boost::spirit;

struct Point {
    double a, b, c;
};

int main(int argc, char **argv) 
{
    vector<Point> points;

    ifstream f("data.txt");

    string str;
    Point p;
    rule<> point_p = 
           double_p[assign_a(p.a)] >> ',' 
        >> double_p[assign_a(p.b)] >> ',' 
        >> double_p[assign_a(p.c)] ; 

    while (getline(f, str)) 
    {
        parse( str, point_p, space_p );
        points.push_back(p);
    }

    // Do something with points...

    return 0;
}

使用Boost.Tuples的樂趣:

#include <boost/tuple/tuple_io.hpp>
#include <vector>
#include <fstream>
#include <iostream>
#include <algorithm>

int main() {
    using namespace boost::tuples;
    typedef boost::tuple<float,float,float> PointT;

    std::ifstream f("input.txt");
    f >> set_open(' ') >> set_close(' ') >> set_delimiter(',');

    std::vector<PointT> v;

    std::copy(std::istream_iterator<PointT>(f), std::istream_iterator<PointT>(),
             std::back_inserter(v)
    );

    std::copy(v.begin(), v.end(), 
              std::ostream_iterator<PointT>(std::cout)
    );
    return 0;
}

請注意,這並不完全等同於您問題中的Python代碼,因為元組不必在單獨的行上。 例如,這個:

1,2,3 4,5,6

將給出相同的輸出:

1,2,3
4,5,6

由你來決定這是一個錯誤還是一個功能:)

您可以逐行從std :: iostream中讀取文件,將每行放入std :: string,然后使用boost :: tokenizer將其拆分。 它不會像蟒蛇那樣優雅/短暫,但比一次閱讀角色中的東西容易得多......

索尼Picture Imagework的開源項目之一是Pystring ,它應該主要直接翻譯字符串分割部分:

Pystring是C ++函數的集合,它使用std :: string匹配python的字符串類方法的接口和行為。 在C ++中實現,它不需要或使用python解釋器。 它為標准C ++庫中未包含的常見字符串操作提供了便利和熟悉

一些例子一些文檔

它遠不如簡潔,當然我沒有編譯。

float atof_s( std::string & s ) { return atoi( s.c_str() ); }
{ 
ifstream f("data.txt")
string str;
vector<vector<float>> data;
while( getline( f, str ) ) {
  vector<float> v;
  boost::algorithm::split_iterator<string::iterator> e;
  std::transform( 
     boost::algorithm::make_split_iterator( str, token_finder( is_any_of( "," ) ) ),
     e, v.begin(), atof_s );
  v.resize(3); // only grab the first 3
  data.push_back(v);
}

所有這些都是很好的例子。 但他們不回答以下問題:

  1. 包含不同列號的CSV文件(某些行的列數多於其他列)
  2. 或者當某些值具有空格時(ya yb,x1 x2 ,, x2)

所以對於那些仍在尋找的人來說,這個課程: http//www.codeguru.com/cpp/tic/tic0226.shtml非常酷......可能需要進行一些更改

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM