0

I have about 3500 full file paths to sort through (ex. "C:\Users\Nick\Documents\ReadIns\NC_000852.gbk"). I just learned that c++ does not recognize the single backslash when reading in a file path. I have about 3500 file paths that I am reading in so it would be overly tedious to manually change each one.

I have this for loop that finds the single backslash and inserts a double backslash at that index. This:

string line = "C:\Users\Nick\Documents\ReadIns\NC_000852.gbk";
    for (unsigned int i = 0; i < filepath.size(); i++) {
        if(filepath[i] == '\') {
            filepath.insert(i, '\');
        }
    }

However, c++, specifically on c::b, does not compile because of the backslash character. Is there a way to add in the extra backslash character with a function?

I am reading the filepaths in from a text file, so they are being read into the string filepath variable, this is just a test.

Nick
  • 823
  • 2
  • 10
  • 22
  • 2
    I suspect you have to use your favorite text editor or another tool, such as `sed`, to modify the file paths. – R Sahu Apr 13 '16 at 05:57
  • 2
    Raw [string literal](http://en.cppreference.com/w/cpp/language/string_literal)? – LogicStuff Apr 13 '16 at 05:59
  • 1
    How about search and replace in notepad ? – Marco Apr 13 '16 at 06:05
  • @marco wow, I totally didn't think of that. Worked great. – Nick Apr 13 '16 at 06:07
  • Note that the standard path separator `/` works with Windows, so you can just change: `C:\Users\Nick\Documents\ReadIns\NC_000852.gbk` to `C:/Users/Nick/Documents/ReadIns/NC_000852.gbk`. – Paul R Apr 13 '16 at 06:37
  • I suspect that you're confusing two things, file paths and string _literals_. The example you show uses a string literal `"C:\Users\Nick\Docu..."` which contains **zero** backslashes. It does contain a lot of illegal escape sequences. But you presumable do not have 3500 file paths in **code**. When you read a single backslash from a text file, it's a single backslash and that's perfectly OK for a Windows file path. – MSalters Apr 13 '16 at 06:49
  • @MSalters I realized that for c++ (not sure with the other languages), according to [this answer](http://stackoverflow.com/questions/11466139/open-file-with-fopen-given-absolute-path-on-windows), that a file path is invalid with the single escape sequence The `filepath` is going to be used to open an `ifstream` and read in from a `.gbz` file. Therefore, my issue was that the loop could not handle the string with the escape sequence. Perhaps my question wasn't worded correctly, but anytime it read in a string with an escape sequence, I would get a compiler error about the "\U" after "C:". – Nick Apr 13 '16 at 07:02
  • @NickPredey: That confirms you are confusing two things. The compiler cannot complain about file paths which are read at runtime; it complains about string literals. C++ is a compiled language: once you have an .EXE, the role of the compiler is done. – MSalters Apr 13 '16 at 07:08
  • @MSalters Ah, yes that makes sense. I appreciate the in depth explanation. – Nick Apr 13 '16 at 07:09

3 Answers3

5

Use double backslash as '\\' and "C:\\Users...". Because single backslash with the next character makes an escape.
Also the string::insert() method's 2nd argument expects number of characters, which is missing in your code.
With all those fixes, it compiles fine:

  string filepath = "C:\\Users\\Nick\\Documents\\ReadIns\\NC_000852.gbk";
  //                   ^^     ^^    ^^         ^^       ^^
    for (unsigned int i = 0; i < filepath.size(); i++) {
        if(filepath[i] == '\\') {
        //                 ^^
            filepath.insert(i, 1, '\\'); 
        }   //                 ^^^^^^^
    }   

I am not sure, how above logic will work. But below is my preferred way:

for(auto pos = filepath.find('\\'); pos != string::npos; pos = filepath.find('\\', ++pos))
  filepath.insert(++pos, 1, '\\');

If you had only single character to be replaced (e.g. linux system or probably supported in windows); then, you may also use std::replace() to avoid the looping as mentioned in this answer:

std::replace(filepath.begin(), filepath.end(), '\\', '/');

I assumed that, you already have a file created which contains single backslashes and you are using that for parsing.
But from your comments, I notice that apparently you are getting the file paths directly in runtime (i.e. while running the .exe). In that case, as @MSalters has mentioned, you need not worry about such transformations (i.e. changing the backslashes).

Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336
1

The problem that you're seeing is because in C++, string literals are commonly enclosed in "" quotes. This brings up one minor problem: how do you put a quote inside a string literal, when that quote would end the string literal. The solution is escaping it with a \. This can also be used to add a few other characters to a string, such as \n (newline). And since \ now has a special meaning in string literals, it's also used to escape itself. So "\\" is a string containing just one character (and of course a trailing NUL).

This also applies to character literals: char example[4] = {'a', '\\', 'b', 0} is an alternative way to write "a\\b".

Now this is all about compile time, when the compiler needs to separate C++ code and string contents. Once your executable is running, a backslash is just one char. std::cout << "a\\b" prints a single backslash, because there's only one in memory. std::String word; std::cin >> word will read a single word, and if you enter one backslash then word will contain one backslash. The compiler isn't involved in that.

So if you read 3500 filenames from a std::ifstream list_of_filenames and then use that to create a further 3500 std::ifstreams, you only need to worry about backslashes in specifying that very first filename in code. And if ou take that filename from argv[1] instead, you don't need to care at all.

MSalters
  • 173,980
  • 10
  • 155
  • 350
0

One way to get rid of special handling of backslash is to keep all file names in a separate disk file as such and use file stream objects such as ifstream to get file names in C++ format.

TCHAR tcszFilename[MAX_PATH] = {0};
ifstream ObjInFiles( "E:\\filenames.txt" );
ObjInFiles.getline( tcszFilename, MAX_PATH );
ObjInFiles.close();

Suppose first file name stored in filenames.txt is "e:\temp\abc.txt" then after executing getline() above, the variable tcszFilename will hold "e:\\temp\\abc.txt".

MNS
  • 1,354
  • 15
  • 26