Reputation: 904
I'm trying to create strings that replace my .png and .jpg files in a directory (all files in it only contain these extensions) with .txt using the .replace command like so:
//say path is directory
path.replace(path.end()-3, path.end()-1, "txt");
It keeps crashing my program though, what am I doing wrong? It's finding the 'png' part properly, but the replacing is not working.
Here's what happens when I do this.
string a = dir.getPath(i); //this is ..\data\images\Test0.png
string b = dir.getPath(i).replace(dir.getPath(i).end()-3, dir.getPath(i).end(), "txt"); //crashes
Upvotes: 2
Views: 454
Reputation: 10936
For readers from the future:
Use the <filesystem>
library to do this for you in one call to std::filesystem::path::replace_extension:
std::filesystem::path d = /* Path to directory */;
for(auto& dir_entry : std::filesystem::directory_iterator{d}) {
if(dir_entry.is_regular_file()) {
auto& p = dir_entry.path();
const auto ext = p.extension();
if(ext == ".jpg" || ext == ".png") {
p.replace_extension(".txt");
}
}
}
Upvotes: 0
Reputation: 310950
It can be done the following way
#include <iostream>
#include <string>
int main()
{
std::string s( "..\\data\\images\\Test0.png" );
std::cout << s << std::endl;
std::string::size_type pos;
if ( ( ( pos = s.rfind( ".png" ) ) != std::string::npos ) ||
( ( pos = s.rfind( ".jpg" ) ) != std::string::npos ) )
{
s.replace( pos, std::string::npos, ".txt" );
}
std::cout << s << std::endl;
return 0;
}
The output is
..\data\images\Test0.png
..\data\images\Test0.txt
Upvotes: 0
Reputation: 1010
Remove the -1 from your second argument.
string path = "filename.png";
path.replace(path.end() - 3, path.end(), "txt");
Results in path storing:
"filename.txt"
Because the first argument indicates where to start replacing characters, the second argument indicates where to stop (you stop AFTER replacing the last character, not 1 position before it), and the last argument specifies what to replace it with.
UPDATE: In response to your updated question, your problem can be answered by asking your self what does dir.getPath(i) return? A new instance of a string. You're trying to traverse from an iterator in one string to an iterator in another string.
Upvotes: 1
Reputation: 726509
If you want to replace the last three characters, you need to provide a range that has three characters. Currently, your range is only two characters in size, i.e from end()-3
, inclusive, to end()-1
, exclusive.
string s("hello.png");
s.replace(s.end()-3, s.end(), "txt");
cout << s << endl;
In addition, you need to make sure that the length of the string is not less than three characters, otherwise accessing end()-3
is undefined behavior.
Also, make sure that you do not use dir.getPath(i)
multiple times, otherwise your end()-3
iterator and end()
iterator point to different strings. I.e.
string b = dir.getPath(i).replace(dir.getPath(i).end()-3, dir.getPath(i).end(), "txt"); // Crashes
// ^^^^^^ ^^^^^^ ^^^^^^^
// Copy # 1 Copy # 2 Copy # 3
needs to be
string b = dir.getPath(i);
b.replace(b.end()-3, b.end(), "txt"); // Does not crash
Upvotes: 1