11

I need a function to convert "explicit" escape sequences into the relative non-printable character. Es:

char str[] = "\\n";
cout << "Line1" << convert_esc(str) << "Line2" << endl:

would give this output:

Line1

Line2

Is there any function that does this?

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
Michele De Pascalis
  • 840
  • 1
  • 9
  • 26

5 Answers5

14

I think that you must write such function yourself since escape characters is a compile-time feature, i.e. when you write "\n" the compiler would replace the \n sequence with the eol character. The resulting string is of length 1 (excluding the terminating zero character).

In your case a string "\\n" is of length 2 (again excluding terminating zero) and contains \ and n.

You need to scan your string and when encountering \ check the following char. if it is one of the legal escapes, you should replace both of them with the corresponding character, otherwise skip or leave them both as is.

( http://ideone.com/BvcDE ):

string unescape(const string& s)
{
  string res;
  string::const_iterator it = s.begin();
  while (it != s.end())
  {
    char c = *it++;
    if (c == '\\' && it != s.end())
    {
      switch (*it++) {
      case '\\': c = '\\'; break;
      case 'n': c = '\n'; break;
      case 't': c = '\t'; break;
      // all other escapes
      default: 
        // invalid escape sequence - skip it. alternatively you can copy it as is, throw an exception...
        continue;
      }
    }
    res += c;
  }

  return res;
}
davka
  • 12,407
  • 11
  • 56
  • 78
  • 1
    Infact I was wondering if that function had been written already. – Michele De Pascalis Apr 10 '11 at 14:18
  • @Glaedr: I am sure it's been written hundred of times, but it's too simple to spend too much time looking. I'd make a quick google search and if I don't find right away I'd write it myself, it's a nice exercise. if you copy the result to a new string it is even simpler as you don't need to shrink your original string and you can accept `const` input – davka Apr 10 '11 at 15:55
  • All right, I set up a function like the one above, and everything works, thanks! – Michele De Pascalis Apr 12 '11 at 13:30
  • 2
    "It's too simple" : it's never simple. when you reinvent the wheel you almost always break canonicalization. there are always obscure features in specifications. for example how will you handle the \u unicode sequences, or the IO/OS specific \n that can get hijacked by the OS especially in file streams in text mode... – v.oddou Feb 04 '19 at 09:38
4

You can do that fairly easy, using the boost string algorithm library. For example:

#include <string>
#include <iostream>
#include <boost/algorithm/string.hpp>

void escape(std::string& str)
{
  boost::replace_all(str, "\\\\", "\\");
  boost::replace_all(str, "\\t",  "\t");
  boost::replace_all(str, "\\n",  "\n");
  // ... add others here ...
}

int main()
{
  std::string str = "This\\tis\\n \\\\a test\\n123";

  std::cout << str << std::endl << std::endl;
  escape(str);
  std::cout << str << std::endl;

  return 0;
}

This is surely not the most efficient way to do this (because it iterates the string multiple times), but it is compact and easy to understand.

Update: As ybungalobill has pointed out, this implementation will be wrong, whenever a replacement string produces a character sequence, that a later replacement is searching for or when a replacement removes/modifies a character sequence, that should have been replaced.

An example for the first case is "\\\\n" -> "\\n" -> "\n". When you put the "\\\\" -> "\\" replacement last (which seems to be the solution at a first glance), you get an example for the latter case "\\\\n" -> "\\\n". Obviously there is no simple solution to this problem, which makes this technique only feasible for very simple escape sequences.

If you need a generic (and more efficient) solution, you should implement a state machine that iterates the string, as proposed by davka.

ollb
  • 1,423
  • 1
  • 11
  • 16
1

I'm sure that there is, written by someone, but it's so trivial that I doubt it's been specifically published anywhere.

Just recreate it yourself from the various "find"/"replace"-esque algorithms in the standard library.

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
0

Here's a cute way to do it on Unixy platforms.

It calls the operating system's echo command to make the conversion.

string convert_escapes( string input )
   {
   string buffer(input.size()+1,0);
   string cmd = "/usr/bin/env echo -ne \""+input+"\"";
   FILE * f = popen(cmd.c_str(),"r"); assert(f);
   buffer.resize(fread(&buffer[0],1,buffer.size()-1,f));
   fclose(f);
   return buffer;
   }
Brent Bradburn
  • 40,766
  • 12
  • 126
  • 136
  • You could similarly do this by generating a little C++ program to print the string, compiling, and running it. That approach is probably a little heavier though. – Brent Bradburn Mar 03 '17 at 15:41
0

Have you considered using printf? (or one of its relatives)

snoofkin
  • 8,449
  • 12
  • 45
  • 84