views:

344

answers:

7
+2  Q: 

String extraction.

Hey guys.

Currently I am working very basic game using the C++ environment. The game used to be a school project but now that I am done with that programming class, I wanted to expand my skills and put some more flourish on this old assignment.

I have already made a lot of changes that I am pleased with. I have centralized all the data into folder hierarchies and I have gotten the code to read those locations.

However my problem stems from a very fundamental flaw that has been stumping me.

In order to access the image data that I am using I have used the code:

string imageLocation = "..\\DATA\\Images\\";

string bowImage = imageLocation + "bow.png";

The problem is that when the player picks up an item on the gameboard my code is supposed to use the code:

hud.addLine("You picked up a " + (*itt)->name() + "!");

to print to the command line, "You picked up a Bow!". But instead it shows "You picked up a ..\DATA\Images\!".

Before I centralized my data I used to use:

name_(item_name.substr(0, item_name.find('.')))

in my Item class constructor to chop the item name to just something like bow or candle. After I changed how my data was structured I realized that I would have to change how I chop the name down to the same simple 'bow' or 'candle'.

I have changed the above code to reflect my changes in data structure to be:

name_(item_name.substr(item_name.find("..\\DATA\\Images\\"), item_name.find(".png")))

but unfortunately as I alluded to earlier this change of code is not working as well as I planned it to be.

So now that I have given that real long winded introduction to what my problem is, here is my question.

How do you extract the middle of a string between two sections that you do not want? Also that middle part that is your target is of an unknown length.

Thank you so very much for any help you guys can give. If you need anymore information please ask; I will be more than happy to upload part or even my entire code for more help. Again thank you very much.

A: 

One thing that looks wrong is that the second parameter to substr should be the number of chars to copy, not the position.

hamishmcn
+1  A: 

item_name.find("..\DATA\Images\") will return the index at which the substring "..\DATA\Images\" starts but it seems like you'd want the index where it ends, so you should add the length of "..\DATA\Images\" to the index returned by find.

Also, as hamishmcn pointed out, the second argument to substr should be the number of chars to return, which would be the index where ".png" starts minus the index where "..\DATA\Images\" ends, I think.

Paul D.
+2  A: 

So combining Paul's and my thoughts, try something like this (broken down for readability):

string extn = item_name.substr(item_name.find_last_of(".png"));
string path = item_name.substr(0, item_name.find("..\\DATA\\Images\\"));
name_ = item_name.substr( path.size(), item_name.size() - extn.size() );

You could simplify it a bit if you know that item name always starts with "..DATA" etc (you could store it in a constant and not need to search for it in the string)

Edit: Changed extension finding part to use find_last_of, as suggested by EarWicker, (this avoids the case where your path includes '.png' somewhere before the extension)

hamishmcn
+3  A: 

Assuming I understand you correctly, the short version of your question is: how do I split a string containing a file path so I have removed the path and the extension, leaving just the "title"?

You need the find_last_of method. This gets rid of the path:

std::size_type lastSlash = filePath.find_last_of('\\');
if (lastSlash == std::string::npos)
    fileName = filePath;
else
    fileName = filePath.substr(lastSlash + 1);

Note that you might want to define a constant as \\ in case you need to change it for other platforms. Not all OS file systems use \\ to separate path segments.

Also note that you also need to use find_last_of for the extension dot as well, because filenames in general can contain dots, throughout their paths. Only the very last one indicates the start of the extension:

std::size_type lastDot = fileName.find_last_of('.');
if (lastDot == std::string::npos)
{
    title = fileName;
}
else
{
    title = fileName.substr(0, lastDot);
    extension = fileName.substr(lastDot + 1);
}

See http://msdn.microsoft.com/en-us/library/3y5atza0(VS.80).aspx

Daniel Earwicker
+3  A: 

using boost filesystem:

#include "boost/filesystem.hpp"

namespace fs = boost::filesystem;

void some_function(void)
{
    string imageLocation = "..\\DATA\\Images\\";
    string bowImage = imageLocation + "bow.png";
    fs::path image_path( bowImage  ); 
    hud.addLine("You picked up a " + image_path.filename() + "!");  //prints: You picked up a bow!
Raz
+6  A: 

In all honeasty, you're probably approaching this from the wrong end.

Your item class should have a string "bow", in a private member. The function Item::GetFilePath would then (at runtime) do "..\DATA\Images\" + this->name + ".png".

The fundamental property of the "bow" item object isn't the filename bow.png, but the fact that it's a "bow". The filename is just a derived proerty.

MSalters
A: 

Thank you all, your answers have been really helpful and I really appreciate how you all answered it in a different way so now I have learned a lot more then just what I was asking and it has piqued my interest in areas of the libraries that I didn't know were around.

Samuel