Inputting string and intergers from a text file into variable - c++

Hey is it possible to have a text file which its contents are:
Weapon Name: Katana
Damage: 20
Weight: 6
Is it possible to assign these bits of information into member variables of a weapons class?.
So that when i call getWeaponName in my main i will get Katana?
I was looking around google and i can get the whole text file input but its not assigned to any variable.
The code i have so far is:
Weapons :: Weapons()
{
this->weaponName = "";
this->damage = 0;
this->weight = 0;
}
Weapons :: Weapons(string weaponName,int damage,int weight)
{
this->weaponName = weaponName;
this->damage = damage;
this->weight = weight;
}
void Weapons :: getWeapon()
{
ifstream myfile ("Weapons\\Katana.txt");
string line;
if (myfile.is_open())
{
while (myfile.good())
{
getline (myfile,weaponName,'\t');//This line gets the entire text file.
//getline (myfile,damage,'\t');
//getline (myfile,weight,'\t');
//myfile >> weaponName;
//myfile >> damage;
//myfile >> weight;
cout << weaponName<< "\n";
}
myfile.close();
}
else
{
cout << "Unable to open file";
}
}
Thanks in advance.

Change
getline (myfile, weaponName, '\t');
to
getline (myfile, weaponName);
What your version is doing is telling getline to grab everything in the file, up to a tab character, and I'm guessing you don't have any tab characters. The version I'm recommending - with no delimiter specified - will get characters up to a newline. So it should read in Weapon Name: Katana.
Then you still need to extract "Katana". Assuming your input file has a very fixed format, you can simply do something like
weaponName = weaponName.substr(weaponName.find_first_of(':') + 2);
This will take the substring starting at the position 2 after the ':'.
Edit
Using weaponName is not exactly proper for your getline statement. weaponName is a string, but at that point, you're just looking for a line. You already have the proper variables in place in getWeapon(). We just need to use them:
void Weapons :: getWeapon()
{
ifstream myfile ("Weapons\\Katana.txt");
string line;
string number;
if (myfile.is_open())
{
while (myfile.good())
{
getline (myfile,line);
weaponName = line.substr(line.find_first_of(':') + 2);
getline (myfile,line);
number = line.substr(line.find_first_of(':') + 2);
damage = atoi(number.c_str());
getline (myfile,line);
number = line.substr(line.find_first_of(':') + 2);
weight = atoi(number.c_str());
cout << weaponName<< "\n";
}
myfile.close();
}
else
{
cout << "Unable to open file";
}
}
Note: you'll need to #include <stdlib.h> for atoi to work.
Honestly, this still isn't very robust. Others have offered you better solutions for looking at the input to see what the data is, and reading and storing all your data, but this should show you the very basics.

You will need to parse each line of your file. So, change the function
getline(myfile, weaponName, '\t');
to
getline(myfile, weaponName);
and parse result.
Do something like that:
#include <cstdio>
#include <string>
using namespace std;
int main()
{
string line = "Weapon Name: Katana";
int pos = line.find(':');
string weaponName;
if ( line.substr(0, pos) == "Weapon Name")
weaponName = line.substr(pos+1, line.npos);
printf("%s\n", weaponName.c_str());
}

First, you need/want to distinguish between "weapons" (plural) and a single weapon. To make much sense, each individual weapon has the characteristics you're reading (name, weight, damage). So, weapons will be a collection of individual weapon objects, each of which has the characteristics.
Based on that, we can attempt to write some meaningful code:
class weapon {
std::string name;
int damage;
int weight;
public:
std::string get_name() { return name; }
Now, we want a weapon to be able to "reconstitute" itself from data stored in a file. Note, however, that right now we're writing a weapon class, so we're only going to deal with one weapon, not a whole collection of them:
friend std::istream &operator>>(std::istream &is, weapon &w) {
std::ignore(is, 1024, ':'); // ignore the "Weapon Name:" header
std::getline(is, w.name);
std::ignore(is, 1024, ':'); // ignore the "Damage:" header
is >> w.damage;
std::ignore(is, 1024, ':'); // ignore the "Weight:" header
is >> w.weight;
return is;
}
Though we don't need it just yet, let's create a matching function to write out a weapon in the correct format as well:
std::ostream &operator<<(std::ostream &os, weapon const &w) {
return os << "Weapon Name: " << w.name << "\n"
<< "Damage: " << w.damage << "\n"
<< "Weight: " << w.weight << "\n";
}
With that, we can read the data for a single weapon. Then we need some way to store multiple weapons. Lacking a reason to do otherwise, our first choice for that is normally an std::vector. If we want to fill that with the data from a file, we can do it something like this:
// open a file of all the weapons data:
std::ifstream in("weapons.txt");
// initialize the vector from the data in the file:
std::vector<weapon> weapons((std::istream_iterator<weapon>(in)),
std::istream_iterator<weapon>());
With this in place we can (for example) list all the weapons (here we're going to use the "operator<<" we defined above):
std::copy(weapons.begin(), weapons.end(),
std::ostream_iterator<weapon>(std::cout, "\n"));
If we want an abbreviated list with just the name of each weapon, we can do something like this:
for (auto const &w : weapons)
std::cout << w.get_name() << "\n";

Your format looks like a variant of a typical .ini file. There
are lots of parsers around for that, if you can modify the
format to make it conform. That would be by far the easiest
solution. Otherwise: how are the various weapons separated in
the file? Is it by an empty line, or is it because the first
entry is always "Weapon Name"? In the first case, I would use
something like the following to read the file (in a free
function, not as a member):
std::auto_ptr<Weapon> currentWeapon;
Line line;
int lineNumber = 0;
while ( source >> line ) {
++ lineNumber;
if ( line.empty() ) {
if ( currentWeapon.get() != NULL ) {
weaponCollection.insert( currentWeapon );
}
currentWeapon.release();
} else {
Line::const_iterator pivot
= std::find( line.begin(), line.end(), ':' );
if ( pivot == line.end() ) {
// Output error message, using lineNumber...
} else {
if ( currentWeapon.get() == NULL ) {
currentWeapon.reset( new Weapon );
}
std::string key( strip( std::string( line.begin(), pivot ) ) );
std::string value( strip( std::string( pivot + 1, line.end() ) ) );
if ( key == "WeaponName" ) {
currentWeapon->weaponName = value;
} else if ( key == "Damage" ) {
currentWeapon->damage = asInt( value );
} else if ( key == "Weight" ) {
currentWeapon->weight = asInt( value );
} // ...
else {
// output error message...
}
}
}
}
Line is a class in my toolbox, that I use a lot for this sort
of thing. It's basically:
class Line : private std::string
{
public:
typedef std::string::iterator iterator;
// ...
using std::string::empty;
using std::string::begin;
// ...
};
The only difference between it and std::string is that its
operator>> calls std::getline, then "cleans up" the results,
by removing any trailing white space (including a possible
'\r', because the file was written under Windows, but I'm
reading it under Unix); in this case, it might be useful to make
it also remove any leading white space. (Mine also has
a manipulator which sets a comment character; if this is set, it
removes any text from this character to the end of the line,
before trimming trailing whitespace.
(From experience: do provide some sort of facility for commenting
in the file. You'll regret it if you don't.)
And asInt is, of course:
int
asInt( std::string const& original )
{
std::istringstream s( original );
int results;
s >> results >> std::ws;
if ( !s || s.get() != EOF ) {
// Error...
}
return results;
}
Again, something that you should have in your toolbox already.
If the key to a new weapon is the "Weapon Name" attribute,
skip the empty line business (or treat empty lines as comments),
and store any existing Weapon and create the new one in the
handling for "Weapon Name".
If you throw on error, above, you'll need to use a try...catch
block to output the error and continue. You might also want to
mark that there was an error somewhere, and abort the game if
so.

Related

How to read a number from a file and use it as a variable in C++?

Let's say I have a file I'm reading that goes something like this :
#character posX posY //commentary line: explains what it represents
CharacterName1 50.0 0.0
CharacterName2 32.0 50.0
The goal here is to be able to read the posX et posY and convert them in my C++ program into 2 double variables x and y.
For now, all I'm able to do is to start reading the file and see if the line corresponds to an empty line or a commentary line.
Then, if the reading line finds the corresponding character name, i should be able to to continue reading this line to get the posX and the posY, but I have no clue on how to do that. I don't know how to skip the blank and how to start reading the number and how to finish reading it to then convert it into double.
Any idea on how I should do that ?
I truly hope this is clear enough.
Thank you in advance.
Attempt example
void loadMap(std::string const& filepath) {
std::ifstream infile(filepath.c_str());
if(infile.fail()) {
std::cerr << "Error... " << std::endl;
} else { /opening occured correctly
while ( !infile.eof() ) {
std::string line;
std::getline(infile, line);
if ( (line[0] != '#') or (line.empty()) ) { //if line not comment or not empty
if( line.find("CharacterName1") ) {.......
Then I'm lost.
Hope this piece of code will help.
#include <bits/stdc++.h>
using namespace std; //change headers and namespaces; included for ease of use;
vector<string> split(const string &text, const char sep) {
vector<string> tokens;
std::size_t start = 0, end = 0;
while ((end = text.find(sep, start)) not_eq string::npos) {
tokens.emplace_back(text.substr(start, end - start));
start = end + 1;
}
tokens.emplace_back(text.substr(start));
return tokens;
}
int main()
{
ofstream outdata;
outdata.open("example.txt");
if( not outdata ) {
cerr << "Error: file could not be opened" << endl;
exit(1);
}
outdata<<"CharacterName1"<<','<<10.0<<','<<40.0<<endl; //writing data into file
outdata<<"CharacterName2"<<','<<20.0<<','<<30.0<<endl;
outdata<<"CharacterName3"<<','<<30.0<<','<<20.0<<endl;
outdata<<"CharacterName4"<<','<<40.0<<','<<10.0<<endl;
outdata.close();
ifstream inputFile;
inputFile.open("example.txt",fstream::in);
if (inputFile.fail())
{
cerr<<"Error: file could not be opened"<<endl;
exit(1);
}
string line;
vector<string> col1;
vector<double> col2;
vector<double> col3;
while (getline(inputFile, line))
{
if(not line.empty()){
auto lineData = split(line, ','); //separator can change in your case
col1.emplace_back(lineData[0]);
col2.emplace_back(std::stof(lineData[1]));
col3.emplace_back(std::stof(lineData[2]));
}
}
for(int i =0; i<(int) col1.size();i++) //printing the data;
cout<<col1[i]<<"\t"<<col2[i]<<"\t"<<col3[i]<<"\n";
return 0;
}
understand the above logic through the following approach:
read each line of the file.
for each line we will separate the column data through the split(string, sep) function which will return a vector<string> containing data of the row. Here sep is the separator used in the file; as I made input file comma-separated, I used ','
converting the returned vector<string> type row-data into appropriate data type and storing in respective column vector col1, col2, col3.
reference of split() functionality.
for another column that may have some missing data
you can add some logic like
if(lineData.size() > 3)
col4.emplace_back(std::stof(lineData[3]));
else
col4.emplace_back(0.0);
after col3.emplace_back(std::stof(lineData[2])); line.

Ignoring empty line during fstream

Writing a program to read a text file and storing it in a struct. An example of the text file:
chicken
dog
car
765
When there is some text in the line, it will get store into the struct. I have tried the following:
getline(file, aLine);
Info.animalchicken = aLine;
getline(file, aLine);
Info.animaldog = aLine;
getline(file, aLine);
Info.car = aLine;
getline(file, aLine);
Info.number = aLine;
I realised that the getline is literally getting every single line. When I run this in my program, the chicken will be stored in the struct Info.animalchicken. The next line, which is empty, will store into Info.animaldog. Dog will be stored in Info.car and so on.
I think a control loop is required here but can't think of a good one. How can I ignore the empty line so my text can enter into the struct correctly?
This is my struct
struct Info {
string animalchicken;
string animaldog;
string car;
int number;
}
The loop idea, while quite primitive, should do the trick; the easiest way would be to wrap the logic in a separate function:
std::string getlineFilterEmpty(std::istream& s) {
std::string line;
do {
if (!s) {
throw std::runtime_error("End of stream");
}
getline(s, line);
} while(line.size() == 0);
return line;
}
Then getting your values is as simple as:
Info.animalchicken = getlineFilterEmpty(file);
Info.animaldog = getlineFilterEmpty(file);
Info.car = getlineFilterEmpty(file);
The number member will require parsing the string to an integer, the code for which you'll find elsewhere on SO.
The logic needs to go something like,
Read a line.
If read succeeded
If line not empty
Provide line
Else
Try again
Else
Handle error
Translating that into code and bundling it into a function for easy reuse, we get
std::string getNotEmptyLine(std::istream & in)
{
while (true) // repeat forever!
{
std::string temp;
std::getline(in, temp); // get a line
if (in) // test the line
{
if (line.size() != 0) // line not empty
{
return temp; //give it to caller
}
}
else
{
// handle error. We'll throw an exception, but this isn't the best solution
throw std::runtime_error("Couldn't read a line!");
}
}
}
As with all literal translations, it needs a bit of work. It would also be helpful to make this function work exactly like getline so the caller can use it as a drop-in replacement.
std::istream & getNotEmptyLine(std::istream & in, // stream to read
std::string & line, // somewhere to put the string
char delim = '\n') // allow different delimiters
{
while (true) // repeat forever!
{
if (std::getline(in, line, delim)) // get a line right in line and test that we got it.
{
if (line.size() != 0) // line not empty
{
break; // success. exit.
}
}
else
{
// line will contain whatever this implementation of `getline` puts or
// leaves in the string on failure.
break; // fail. Let the caller decide what to do
}
}
return in;
}
Usage:
Info info;
std::string aLine;
if (getNotEmptyLine(in, info.animalchicken) &&
getNotEmptyLine(in, info.animaldog) &&
getNotEmptyLine(in, info.car) &&
getNotEmptyLine(in, aLine))
{
info.number = std::stoi(aLine);
}
else
{
// handle error
}
Note: even this may be too simplistic. It can't handle a line that contains nothing but whitespace. A single misplaced and nigh-invisible space will wreak havoc. If this is a concern, add more logic to if (line.size() != 0)
Here's an option adding stream operators and a helper function to skip empty lines.
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
struct Info {
std::string animalchicken;
std::string animaldog;
std::string car;
int number;
};
// a helper function to do getline but skip empty lines
std::istream& getline_with_content(std::istream& is, std::string& s) {
while(std::getline(is, s)) if(not s.empty()) break;
return is;
}
// an istream operator to read one Info
std::istream& operator>>(std::istream& is, Info& i) {
getline_with_content(
getline_with_content(
getline_with_content(is,
i.animalchicken),
i.animaldog),
i.car);
is >> i.number;
// ignore everything after the number until a newline appears:
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return is;
}
// an ostream operator to print one Info
std::ostream& operator<<(std::ostream& os, const Info& i) {
return os << i.animalchicken << '\n'
<< i.animaldog << '\n'
<< i.car << '\n'
<< i.number << '\n';
}
int main() {
// an example istream with a lot of blank lines:
std::istringstream file(
"chicken\n\n"
"dog\n\n"
"car\n\n\n"
"765\n");
Info i;
file >> i; // read one Info from the stream
std::cout << i; // print one Info
}
Demo

How can I search for a employee record (by name) in a text file and only display it's details?

I am making a program where I input the details of many employees and store it in a text file. How can I make a function to search the entire text file and display the only details of that employee and not anyone else's?
The details is always being inputted in append mode. I can't use eof() as it will display the entire document.
This is a school project and we have only studied cin and cout and not std::, hence I am using using namespace std;
EDIT: ADDED SAMPLE TEXT FILE
First name:Test
Last name: asdfas
Employee no: 12
(etc.)
Local Contact: 12323
***********************************************
First name:Test2
Last name: asd
Employee no: 23432
(etc.)
Local Contact: 234324
***********************************************
void hr::empdetails()
{
//declaring all datamembers
char firstname [30], lastname [30], dept[30]; //etc.
ofstream outfile;
outfile.open ("example.txt",ios::app);
//inputting all details
//writing details into text file...
outfile<<"First name:";
outfile<<firstname;
//...................
outfile<<"\nLocal Contact: ";
outfile<<localcon;
outfile<<"\n\n*************************************************";//indicating end of employee's details
}
void hr::searchname()
{
//what should i write here to search for a name and display all of its details
}
In most cases, the method is to read in all the fields in a record and only use the fields that you need. Reading the extra fields will not take any extra time versus executing code to skip over them.
Also, prefer arrays (std::vector) of structures to parallel arrays:
struct Employee_Record
{
std::string first_name;
std::string last_name;
int id;
//...
};
std::vector<Employee_Record> database;
Employee_Record array[32];
You can make the input simpler by overloading operator>> for the structure:
struct Employee_Record
{
//...
friend istream& operator>>(istream& input, Employee_Record& er);
};
istream& operator>>(istream& input, Employee_Record& er)
{
getline(input, er.first_name);
getline(input, er.last_name);
//...
return input;
}
You input code would look something like this:
std::vector<Employee_Record> database;
Employee_Record er;
while (data_file >> er)
{
database.push_back(er);
}
A common technique is to read in all the data, then process the data (such as searching).
int main()
{
ifstream fin("look.txt");. // Here you have to provide file name
string line; // takes a line at a time.
int person = 1; // this increments person
while (getline(fin, line)) // here we are reading data line by line till eof
{
if (line == "***********************************************") // this is point where we increment the person variable by one ( to change person )
person++;
int ind = line.find_last_of(':'); // here we are finding ':' character to get fields name like First Name , Last Name ,etc..
string cc = line.substr(0, ind); // here we get value of the fields ex:- First Name :-Sha11 ( here we fetch Sha11 .. you use this way to compare empolyees various value ,in your desired way.. )
if (cc == "First name" || cc == "Last name" || cc == "Local Contact") ( It is looking only for some desired fields , but you might change this according to you. )
{
if (ind != string::npos)
{
int diff = line.size() - ind - 1;
string pa = line.substr(ind + 1, diff);
cout << person << " : " << cc << " : " << pa << endl; // here cc stores the field's name and pa stores the field's value. here i used substr() and find() to get desired results from the string (for more details about these function look at these urls "www.cplusplus.com/reference/string/string/find/" , "http://www.cplusplus.com/reference/string/string/substr/")..
}
}
}
return 0;
}
This commented explanation might help you...!
This might solve your problem....

Formatted input from string in c++

I am making a statistics collector that reads the log of a music player and lets the user show top ten most played etc. As a noob project.
A line from the log looks like: "20:42:03 start E:\ROTATION\A\HÃ¥kan Lidbo - Dammlunga.mp3"
I have put this in a string using ifstream and getline.
Then making an array of chars of the string using
const char *charveqtur = newline.c_str();
Then I tried to sort i out with sscanf:
sscanf (charveqtur, "%d:%d:%d\tstart\t%s", &this->hour, &this->minute, &this->second, &this->filename);
The problem is that the filename is cut at the first space. I have also tried using istringstream instead but no breakthrough so far.
Which is the most convinient way of doing this? Thanks.
You can use some input stream to read the first integers and colons, and because the filename is the last entity, you can then use std::getline. However, even if your filename is not the last part, note that std::getline is quite a versatile function that accepts any delimiter.
A more advanced method would be to define your own type for filenames and overload operator>>(std::istream &, T const &) on it.
Here is a complete example using std::getline and stringstream with basic diagnostics and some reformatting:
#include <sstream> // for istringstream
#include <iostream> // for cout and cerr
#include <iomanip> // for setprecision
#include <cmath>
bool read (std::string const &line) {
char c = 0;
double length;
double rating;
std::string title;
std::istringstream ss;
ss.str (line);
ss >> length;
if (!ss.good()) { std::cerr << "invalid length\n"; return false; }
if (ss.get()!=':') { std::cerr << "expected colon\n"; return false; }
ss >> rating;
if (!ss.good()) { std::cerr << "invalid rating\n"; return false; }
if (ss.get()!=':') { std::cerr << "expected colon\n"; return false; }
std::getline (ss, title);
double sink;
std::cout << title << " ("
<< int(length) << ':' << 60*std::modf (length,&sink)
<< " min), your rating: " << rating << '\n';
return true;
}
int main () {
read ("30.25:5:Vivaldi - The four seasons.ogg");
read ("3.5:5:Cannibal Corpse - Evisceration Plague.ogg");
read ("meh");
return 0;
}
Output:
Vivaldi - The four seasons.ogg (30:15 min), your rating: 5
Cannibal Corpse - Evisceration Plague.ogg (3:30 min), your rating: 5
invalid length
Important: When parsing, you are sailing close to the security risks. Always be conscious and sensible and try to use tested and proven libraries where possible. This also implies that you do not use sscanf, which is not typesafe, error-prone and sometimes hard to get right.
Don't use C if you have C++, and used correctly, iostreams are even more convenient than printf/scanf+co.
You could perhaps do something like
int lastpos = 0;
if sscanf (charveqtur, "%d:%d:%d\tstart\t%n", &this->hour,
&this->minute, &this->second,
&lastpos) > 3 && lastpos >0) {
std::string filename = newline.substr(lastpos);
/* do something with filename */
}

c++, using get and >> for ifstream

I have a text file that I am inputting data in from, but I can't seem to get it right.
Here are two lines from the text file as an example (these aren't real people don't worry):
Michael Davidson 153 Summer Avenue Evanston CO 80303
Ingrid Johnson 2075 Woodland Road Aurora IL 60507
Here is the code I have to load the text file and put the data into a struct. I am still new to C++(obviously) and I'm having a hard time using get and >> together. The code I have below, works fine until I get to the "state" and then something goes wrong. Thanks for the help!
//constants
const int FIRST_NAME_LEN = 11;
const int LAST_NAME_LEN = 13;
const int ADDRESS = 25;
const int CITY_NAME_LEN = 16;
const int STATE_LEN = 3;
//define struct data types
struct CustomerType {
char firstName[FIRST_NAME_LEN];
char lastName[LAST_NAME_LEN];
char streetAddress[ADDRESS];
char city[CITY_NAME_LEN];
char state[STATE_LEN];
int zipCode;
};
//prototype function
ifstream& getInfo(CustomerType& CT_Struct, ifstream& infile);
int main() {
//declare struct objects
CustomerType CT_Struct;
ifstream infile("PGM951_customers.txt");
if(!infile) {
cerr << "Could not open the input file." << endl;
exit(1); //terminates the program
}
//call the function
getInfo(CT_Struct, infile);
return 0;
}
ifstream& getInfo(CustomerType& CT_Struct, ifstream& infile) {
while(infile) {
infile.get(CT_Struct.firstName, sizeof(CT_Struct.firstName));
infile.get(CT_Struct.lastName, sizeof(CT_Struct.lastName));
infile.get(CT_Struct.streetAddress, sizeof(CT_Struct.streetAddress));
infile.get(CT_Struct.city, sizeof(CT_Struct.city));
infile.get(CT_Struct.state, sizeof(CT_Struct.state));
infile >> ws;
infile >> CT_Struct.zipCode;
cout << CT_Struct.firstName << " | " << CT_Struct.lastName << " | " << CT_Struct.streetAddress
<< " | " << CT_Struct.city << " | " << CT_Struct.state << " | " << CT_Struct.zipCode << endl;
}
return infile;
}
=== edit ===========
Reading in the state at 8 char was just me messing around and then I forgot to change it back...sorry.
The problem is istream::get() breaks for streetAddress which has spaces in it.
One way is to tokenize the input line first into say, a vector of strings and then depending on the number of tokens convert these to appropriate fields of your CustomerType:
vector<string> tokenize(string& line, char delim=' ') {
vector<string> tokens;
size_t spos = 0, epos = string::npos;
while ((epos = line.find_first_of(delim)) != string::npos) {
tokens.push_back(line.substr(spos, epos - spos));
spos = epos;
}
return tokens;
}
I'd rather a stream extraction operator for CustomerType :
struct CustomerType {
friend istream& operator>>(istream& i, CustomerType& c);
string firstName, lastName, ...;
// ...
};
istream& operator>>(istream& i, CustomerType& c) {
i >> c.firstName >> c.lastName;
string s1, s2, s3;
i >> s1 >> s2 >> s3;
c.streetAddress = s1 + s2 + s3;
i >> c.city >> c.state >> c.zipCode;
return i;
}
You're getting 8 characters for State, which includes all your zipcode, and is larger than your field.
It'd also be tempting to use the skipws operator:
infile >> skipws >> CT_Struct.firstName
>> CT_Struct.lastName
>> ... ;
(Update: that's what I get for doing that from memory. This is more closely approximating correct.)
If I were you I would start again from scratch. I would:
use std::strings instead of character arrays for your data
reads line at a time from the file using std::getline
parse the line up using a stringstream
avoid mixing formatted and unformatted input
My approach to this would be the following:
1) Read each line into a null terminated buffer.
2) Use a split() function that you're gonna have to write. This function should take a string as its input and return a list. It should also take a separator. The separator in this case is ' '.
3) iterate over the list carefully (are there never middle names?) What about 1 word, or 3 word street names? Since many of these columns are really variable in number of words, and you have no seperator other than whitspace, this may prove a fairly tough task. If you NEVER have middle names, you could assume the first two columns are first and last name. You know for sure what the last two are. Everything between them could be assigned to a single address field.