从文本文件中读取具有不同分隔符的行和列

时间:2013-09-18 16:08:39

标签: c++

我正在尝试编写一个从文本文件中读取单个行的函数。每行有两列或三列。我想知道最优雅/最干净的方法。我需要使用函数来处理不同的分隔符(\t,\n,' ',',',';')

除了不同的分隔符之外,我的方法正常工作。

E.g。输入:

6
0 0
1 1
2 2
3 3
4 4
5 5
10 
0 1 0.47
2 0 0.67
3 0 0.98
4 0 0.12
2 1 0.94
3 1 0.05
4 1 0.22
3 2 0.24
4 2 0.36
4 3 0.69

模式输入:

[total number of vertices]
[id-vertex][\separetor][name-vertex]
...
[total number of edges]
[id-vertex][\separator][id-neighbor][\separetor][weight]
...
*\separetor=\t|\n|' '|','|';'

我的方法:

void readStream(istream& is, const char separator) {
    uint n, m;
    is >> n;
    cout << n << endl;
    string name;
    uint vertexId, neighborId;
    float weight;
    while(!is.eof()) {
        for(uint i = 0; i < n; i++) {
            is >> vertexId >> name;
            cout << vertexId;
            cout << " " << name << endl;
        }
        is >> m;
        cout << m << endl;
        for(uint j = 0; j < n; j++) {
            is >> vertexId >> neighborId >> weight;
            cout << vertexId;
            cout << " " << neighborId;
            cout << " " << weight << endl;
        }
        break;
    }
}

概述:

  1. 问题:不同的分隔符。

  2. 其他人提出解决方案:一般来说,有人有其他优雅/清洁的解决方案吗?

5 个答案:

答案 0 :(得分:1)

您可以使用boost split它可以在您可以指定的多个分隔符上拆分字符串。

std::string = line;
std::vector<std::string> parts;

boost::split(parts, line, boost::is_any_of("\t\n,; "));

答案 1 :(得分:0)

您可以使用(考虑到您的文件将始终采用上述格式)

fstream file;
file.open("abc.txt",ios::in);
int numOfVertices;
string line;
getline(file, line);
numOfVertices = stoi(line);
vector<int> xCoord;
vector<int> yCoord;
while((--numOfVertices)>=0) 
{
    string line;
    getline(file, line);
    std::size_t prev = 0, pos;
    pos = line.find_first_of(" ';", prev);
    xCoord.push_back(stoi(line.substr(prev, pos-prev)));
    prev = pos+1;
    pos = line.find_first_of(" ';", prev);    //considering some of the delimiters
    yCoord.push_back(stoi(line.substr(prev, pos-prev)));
}

这是添加顶点。同样,您也可以提取边缘。

答案 2 :(得分:0)

如果你确定分隔符不是空格,你可以将它们扔进垃圾桶(例如后面的​​分隔符)

is >> vertexId >> separator >> neighborId >> separator >> weight;

答案 3 :(得分:0)

以下代码可能有用:

int t1,t2;
double t3;//global variables...
void parse_Vertex_Line(char *str)
{
     int tmp=0;
     char *p=str;
     //extract the vertex-id
     while(*p >='0' && *p <='9')
        tmp = tmp*10 + *(p++) -'0';
     t1=tmp;
     tmp=0;
     p++;
     //now extract the vertex-name..
     while(*p >='0' && *p <='9')
        tmp = tmp*10 + *(p++) -'0';
     t2=tmp;
     return;
}

void parse_Edge_Line(char *str)
{
     //extracting the first two numbers is just the same...
     int tmp=0;
     char *p=str;
     //extract the first vertex-id
     while(*p >='0' && *p <='9')
        tmp = tmp*10 + *(p++) -'0';
     t1=tmp;
     tmp=0;
     p++;
     //now extract the second vertex-id..
     while(*p >='0' && *p <='9')
        tmp = tmp*10 + *(p++) -'0';
     t2=tmp; 
     p++;
     //but extracting a double value is a bit different...
     //extract the weight...
     int before_decimal=0, after_decimal=0;
     while(*p!='.')
         before_decimal = before_decimal*10 + *(p++) -'0';
     p++;
     int no_of_digits=0;
     while(*p>='0' && *p<='9')
     {
         after_decimal = after_decimal*10 + *(p++) -'0';
         no_of_digits++;
     }
     //assign it to the global double variable...
     t3 = before_decimal + (after_decimal/pow(10.0, no_of_digits));
}

现在你要做的是先获得number of vertices(n)。接下来阅读每个n行。 每次调用函数parse_Vertex_Line。然后阅读number of edges并同样每次调用parse_Edge_Line。提取值并存储它们。

此代码适用于几乎所有分隔符。希望这看起来很优雅。

答案 4 :(得分:0)

我为此方案修改了我的其他帖子:Override istream operator >> and modify delimiter(对此的解释是此处接受的解决方案的第一个变体,用于可能的实现)。

一般来说,一种可能处理不需要的分隔符的方法是将它们变成空格!

我的方法可以为操作&gt;&gt;'使用新的分隔符来自istream:

struct delimiterIsSpace : ctype<char> {
    delimiterIsSpace() : ctype<char>(get_table()) {}
    static mask const* get_table() {
        static mask rc[table_size];
        rc[';'] = ctype_base::space;
        rc[','] = ctype_base::space;
        rc[' '] = ctype_base::space;
        rc['\t'] = ctype_base::space;
        rc['\n'] = ctype_base::space;
        return &rc[0];
    }
};

使用方法:

cin.imbue(locale(cin.getloc(), new delimiterIsSpace));

for (int a, b; cin >> a >> b; ) {
    cout << "a=" << a << " b=" << b << "\n";
}