Read/write data then separate data
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
}
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...
}
}
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.
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.
精彩评论