Skip to main content
gamedev.net
🔒 Locked

C++ std::string manipulation

Started by RASP 5 replies 500+ views
Original Post
RASP
RASP
I'm currently writing a cricket management simulation using C++ and eventually DirectX for the GUI. For the match engine, I'm using a 'Commentary handler' class which is given an 'event' such as a batsman playing a shot. Here is where the problems begin. I want the 'Commentary handler' to open the "match_events.cfg" file and find the line which corresponds to the given event. So for a wicket falling in the config file I would have: # EVENT_WICKET_LOSS G : (p1) has bowled (p2) R : (p1) bowled (p2) Now ' G : ' is for in the game reporting and ' R : ' is for past tense reporting. The file will eventually have hundreds of these lines of commentary. I want the 'Commentary handler' to go through and the right one. Once it has found the correct line. I want it to read in the line of commentary and then replace (p1) and (p2) with a player's name such as "McGrath". Any suggestions on how I can do this type of thing?
Hamster
Hamster
This might have some helpful info

http://www.kbcafe.com/articles/CPP.Tricks.pdf

as regards actually finding it in the file, I''m not sure - personally I''d probably just try and load the strings into memory at program start (either a fixed size or dynamic array), and maybe use a set of #defines or something similar to allow me to ask for the commentary_string[ EVENT_WICKET_LOSS ] when needs be.

That does NOT, however, mean to say that I have a clue what I''m talking about - that may be an awful idea, it''s just how I''d probably proceed with it.
Zipster
Zipster
Well, the first thing you want to try and to is strip and simplify. What I mean is this. Is each event in the exact same format, i.e identifier, game, report? Are they always in this triplet and order? If so, then eliminate the needless G and R tags, because they only get in the way of the real data, and they don't even change order. Is the '#' also needed before each ID? Or can you just store it raw? Because it's also pointless to insert this extra character before each of your search strings.

Once that's done, you can read the file in line by line, searching for you identifier. Once it's found, you know the next to lines are game and report. Once they're in an std::string, you can use the replace functionality to easily, er, replace text

If you want, just read in the whole file once, and store these event IDs and their format strings in a temporary, program-lifetime data structure.

EDIT: Just keep in mind that I'm not writing your program, so I don't know if those tags really are necessary. If they are, then by all means leave them there. But from what you've told us they don't appear to serve any purpose.

[edited by - Zipster on July 15, 2003 7:14:54 AM]
Fruny
Fruny
quote:
Original post by Zipster
If you want, just read in the whole file once, and store these event IDs and their format strings in a temporary, program-lifetime data structure.



A std::map looks mighty good.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
RASP
RASP
Thanks for your replies

Zipster - you''re right the format can be simplified somewhat. Instead it could be:

EVENT_WICKET_LOSS
(p1) has bowled (p2)
(p1) bowled (p2)

So in other words, I need to use search through the file for say, for example, the string "EVENT_WICKET_LOSS". Once it has found this I need to move one line down and read in the line of commentary and store it as a string. Then I use replace to replace the text. Now, I used replace earlier but it didn''t seem to work. Don''t suppose you''d like to provide an example?

The reason I''m not loading in all of the strings into the program at start-up is that different languages of the config file will exist and therefore it makes more sense to load from the correct file at each point commentary is needed than to load each line of commentary for a given language as the user can change the language at any point.

Hamster - I''ll have a look at that now
RASP
RASP
Anyone? This really is rather urgent...
Xai
Xai
actually, you can easily create a class which serves up the appropriate strings ... when asked ... something with functions like:

std::string& GetEventString(EventID eventID);

and the class itself could be told what language you are in, and manage reading the correct file. This way, you can read the file in once, when you are told what language to use, and reread it if they change ... but the rest of the program never needs to know when (or even if) you read the file(s) ... perfect encapsulation ... once you make a class which does all the config file reading, you can play with different file format systems without the rest of your program ever caring ...

for instance ... will the whole set of messages be in one file, or multiple ... if you use a class, this disicion will not matter to the rest of the program.

As for the idea of changing

# EVENT_WICKET_LOSS
G : (p1) has bowled (p2)
R : (p1) bowled (p2)

to

EVENT_WICKET_LOSS
(p1) has bowled (p2)
(p1) bowled (p2)

that''s really fairly silly ... because the original format could support additions like:

# EVENT_WICKET_LOSS
G : (p1) has bowled (p2)
G : (p1) has lost with a score of (p2)
R : (p1) bowled (p2)

to provide alternates .. etc ... in other words, you original format supprts EXTENSION ... so don''t throw that away without a reason ...

And if you wrap the reading/parsing of the file in a class, then the fact that it may be a little harder can be ignored ...

Now, as for how to parse the file ... check out boost''s regular expression library ... amoung other things ... but really all you have to do if find the line matching:

# EVENT_YOU_WANT

and read all lines until you get to the next line starting with

#

then have some factory method which takes a line of text like

G : whatever
or
R : whatever

and creates little stucts/classes to hold the info ...

pick the one you want ...

and call a function (which you must write of course) for something like:

typedef std::deque StringList;
std:string FillMacro(const std::string &macro, const StringList &arguments);

or whatever you want it to look like ...

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.