split string

hi all,
 my program is to  get value in a config file whose format is

servername = ubuntu
port =50000
servername = solaris
port = 37777

I use strrchr() to detect the index of '=' then  copy string and trim a possible of leading space of that string.

I think i have the problem with strrchr() because when it detect '=', it stops, so I need to move forward 1 index to exclude '=' from the string . I have tried, but fail. So please help me.
Also , is there are in better way to achieve same task with better code? tks.

PS: I just want to cover the case =50000 or = 50000, or =      50000 .
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

BeginToLearnAuthor Commented:
how about my code? i don't want too complicated hihi
For that kind of config file, do the following repeatedly in a loop :

    (a) read the next line from the file into a buffer
    (b) use strtok to split up the buffer into a key and a value (using the '=' character as a delimiter)
    (c) clean up the key and value by removing whitespace from the beginning and/or end
    (d) store or use the key/value pair you just read

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
CompTIA Security+

Learn the essential functions of CompTIA Security+, which establishes the core knowledge required of any cybersecurity role and leads professionals into intermediate-level cybersecurity jobs.

In case you are doing that on Window - the file looks suspciously like the .ini file format for which MS has created APIs to read them, it could be as simple as
int nPort = GetPrivateProfileInt("Server2", "port", -1, "config.ini");

Open in new window


http://msdn.microsoft.com/en-us/library/ms724345%28VS.85%29.aspx ("GetPrivateProfileInt Function")
http://msdn.microsoft.com/en-us/library/ms724353%28v=VS.85%29.aspx ("GetPrivateProfileString Function")
BeginToLearnAuthor Commented:
oh jrk, it is not for windows. Its in ubuntu. tks.
BeginToLearnAuthor Commented:
do u mean like this in attachment?
You're not just erasing spaces at the beginning and end, and you're also not taking care of other types of whitespace (like tabs eg.). But that's a good start, yes.
BeginToLearnAuthor Commented:
oh Infinity08,
 you mean besides space ' ', i need to consider tab also?
>>  you mean besides space ' ', i need to consider tab also?

Whitespace includes spaces, tabs, vertical tabs, newlines, carriage returns.
If you want to account for all cases, then you should remove all these types of whitespace from the beginning and end of the key and value.
Try the stringtok template shown for example here http://gcc.gnu.org/onlinedocs/libstdc++/manual/strings.html#strings.string.token

#include <string>
template <typename Container>
stringtok(Container &container, 
          string const &in,
	  const char * const delimiters = " \t\n")
    const string::size_type len = in.length();
    string::size_type i = 0;

    while (i < len)
	// Eat leading whitespace
	i = in.find_first_not_of(delimiters, i);
	if (i == string::npos)
	  return;   // Nothing left but white space

	// Find the end of the token
	string::size_type j = in.find_first_of(delimiters, i);

	// Push token
	if (j == string::npos)
	  container.push_back(in.substr(i, j-i));

	// Set up for next loop
	i = j + 1;

Open in new window

The // Eat leading whitespace comment and the one following the next return are a kind of misleading.  Basically, the i is set to the beginning of the next token, j is set to the following delimiter, and the token is extracted to the container.  More consecutive delimiters is treated as one (here called whitespaces, but in the code they are the charecters from the delimiter argument).  

The usage in your case would be like:

    string s("servername = ubuntu");
    vector<string>  vec;
    stringtok (vec, s, " =");  // both space and '=' as delimiters

Open in new window

Then you can check the size of the vector and get the vec[0] as the "servername" and vec[1] as "ubuntu".  The same template can be used to build a list<string> and set<string>.

However, there is a problem with spaces/'=' inside the value.  You may want to enhance the template by say maxsplit argument to be able to prescribe you wan to split the string say max once.  

However, it is probably better to write your own function that splits the string on the first '=', and returns the pair<string, string> with the name and value.
Looking at your code, you should consider to convert it from C/C++ (i.e. from mixture of both) to pure C++.   You may not like this idea, but it is better to do it sooner than later.

I can see your example to be the ideal one to present looping through the text file, using the finite automaton for parsing of the .ini like files (with sections), using the streams instead of working with buffers and with printf(), etc.
you might consider parsing  the whole config file into a container where you later could easily look-up for sections (like [server1]) and single keys within a section.

to follow pepr's advice you might use a

std::map<std::string, std::map<std::string, std::string> >  config;

Open in new window

as container where the key of the outer map is the 'section' key and the key of the inner map the 'entry' key.

you could read the config file line by line and whenever you have identified a section, entrykey and entryvalue you could add it to the container by

config[section][entrykey] = entryvalue;

and you need not to care whether section or entrykey already exists or not.

BeginToLearnAuthor Commented:
tks a lot for all suggestion. I am reading all now. By the way, please take a look at other questions and http://www.experts-exchange.com/Software/Server_Software/Web_Servers/Apache/Q_26946319.html

BeginToLearnAuthor Commented:
Honestly I want to move to C++ , but sometimes I don't have enough knowledge/skill to move on. That's why you can see i am in the middle of C and C++. ( So i use the orginal version of readConfig as a backup version)

I understand the comments from pepr now. I decide to to combine it with Sara's suggestion to use map because of "where you later could easily look-up for sections (like [server1]) and single keys within a section.

Let me work on it now.
BeginToLearnAuthor Commented:
i have finished the main frame of new readconfig. the only part left is the insert into the map in if ( flag == 3).
I think for insertion to the map, I only use the second element on   vector v1 and v2 to the map?
Am I on the right track?
BeginToLearnAuthor Commented:
i just finished it. I think it is ok. However, i still need  your advise to make sure it usable later on. tks.
There's no reason to use C style I/O or C style string operations. You chose to do this in C++, and to use std::string, so it's better to do that consistently.

Start by renaming your file to .cpp, then replace the C style I/O with C++ style I/O :


And use the std::string functionality :

Thinking in C++ by Bruce Eckel can be bought in paper form but also downloaded in HTML for free -- also excellent book (http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html).  Of course, you should start it from beginning.  The shortcuts to strings and iostream are -- assuming you extract the books to the ThinkinInCpp directory:

3: Strings in Depth -- ThinkingInCpp/Volume2/TicV2.html#_Toc53985657
4: Iostreams -- ThinkingInCpp/Volume2/TicV2.html#_Toc53985673
BeginToLearnAuthor Commented:
Today i checked out Absolute C++ and C++ cookbook . they help me on how to display the map of map :)
You can simply display them using the reverse way that you used when building it.  You can generate the file similar to the one that has been consumed for the input -- i.e. section (keys of the first-level map) with lines id=value where id is the key of the second-level map.

The process is basically two nested loops.  The first loop prints the section and enters the second loop.  The second loop produces pairs (key, value) and you can print them separated by '='.

The only problem is to know how to iterate through all the keys of the map.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.