1

I am a newbie in C++. I am doing a C++ sign up form where I keep all the user datas in a text file named user.txt with formats like

name|password|address|postal|phone

Each user record will occupy one line.

So my first question how can I do this nicely in C++

As for the reading part, my main problem is how to separate the data by splitting "|" then put the records in a user array. So when I do a login function I can loop through the array to match users.

My current code for reading is

string User::readUser(){
    ifstream fin("user.txt");
    string line;
    while(getline(line,fin)){
        string name, password, address; int postal, phone;//put the records into a 2 dimention array
    }
    //return array
}
SethO
  • 2,703
  • 5
  • 28
  • 38
bluedream
  • 999
  • 2
  • 12
  • 15

3 Answers3

1

Check out this answer.

In your case, the fields will be appended to the vector<string> in order, so you can access them directly from it. First position would correspond to the name, second to the password and so on.

Here's an example:

// The elements should be in this order: name, password, address, postal, phone
vector<string> v = split(line, '|');
string name = v[0], password = v[1], address = v[2];

As for your second question, you could create a structure or class that describes the user:

struct User {

    // Using type string for all fields for convenience.
    string name, password, address, postal, phone;

    User(string n, string pw, string a, string p, string ph): name(n),
                                                              password(pw),
                                                              address(a),
                                                              postal(p),
                                                              phone(ph) {}

};

vector<User> uv;

// ...

// Split string, create user instance and append it to the user list
vector<string> v = split(line, '|');
uv.push_back(User(v[0], v[1], v[2], v[3], v[4]));

To iterate over the User vector:

for (int i = 0; i < uv.size(); ++i) {
    if (uv[i].name == "John") {
        // Process John...
    }
}
Community
  • 1
  • 1
Matheus Moreira
  • 17,106
  • 3
  • 68
  • 107
  • Hi, sorry, i am really dumb, i dont understand that code actually, do you mind to reconstruct for me..... – bluedream Mar 10 '11 at 17:49
  • hi i have one more question. the vector ouptput is for a single record only, but in my question, i want to store all the users in a single array, so i can loop to match the user, what can i do in this case – bluedream Mar 10 '11 at 17:55
  • Updated my answer, but I didn't test the code. Let me know if it works! – Matheus Moreira Mar 10 '11 at 18:08
  • thanks, last question, how can i loop uv now? for example looping uv to check a user with name "john" – bluedream Mar 10 '11 at 18:21
1

Some time ago I wrote an answer with a C++ sscanf replacement. It fits perfectly for your case:

std::vector<boost::any> user_data;
sscanf(line, "%s|%s|%s|%i|%i", user_data);

Now constructing a User (a struct like in Matheus Moreira's answer) is very simple:

User(boost::any_cast<std::string>(user_data[0]), // name
     boost::any_cast<std::string>(user_data[1]), // password
     boost::any_cast<std::string>(user_data[2]), // address
     boost::any_cast<int>(user_data[3]),  // postal
     boost::any_cast<int>(user_data[4])); // phone

This requires boost's any and lexical_cast.

Community
  • 1
  • 1
Karl von Moor
  • 8,484
  • 4
  • 40
  • 52
  • Nice solution! Just out of curiosity, is it possible to eliminate the `boost` dependency? – Matheus Moreira Mar 10 '11 at 18:51
  • @Matheus Of course you could modify the sscanf replacement to only use `std::string`s, but than it practically would be your solution – so yes, the boost dependency is necessary … or you write your own `any` and `lexical_cast`. – Karl von Moor Mar 10 '11 at 19:02
  • since reading a file, why can we use sscanf instead of fstream?? – bluedream Mar 10 '11 at 23:13
  • @user594649 Of course you read the file with ifstream, I'm just talking of stuff inside the `while(getline())` loop. BTW typing "user594649" isn't that funny – maybe you can think of something better? – Karl von Moor Mar 11 '11 at 10:39
0

The obvious solution would be to use boost::regex on each line: this will do input format checking as well as separate out the fields. Something like:

while ( getline( line, fin ) ) {
    static boost::regex const pattern(
        "\\([^|]+\\)\\|\\([^|]+\\)|\\([^|]+\\)|\\([^|]+\\)|\\([^|]+\\)" );
    boost::smatch match;
    if ( !regex_match( line, match, pattern ) ) {
        //  Error handling...
    } else {
        // match[1] is name, match[2] is password, etc.
    }
}

More complex matching patterns are possible, requiring e.g. postal and phone to be numeric. You could also easily modify it to allow leading and trailing white space as well.

James Kanze
  • 150,581
  • 18
  • 184
  • 329