Преобразовать строку с явной escape-последовательностью в относительный символ - PullRequest
11 голосов
/ 10 апреля 2011

Мне нужна функция для преобразования "явных" escape-последовательностей в относительный непечатаемый символ. Es:

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

даст такой вывод:

Line1

Line2

Есть ли какая-нибудь функция, которая делает это?

Ответы [ 5 ]

14 голосов
/ 10 апреля 2011

Я думаю, что вы должны написать такую ​​функцию самостоятельно, поскольку управляющие символы - это функция времени компиляции , т.е. когда вы пишете "\n", компилятор заменит последовательность \n на символ eol.Результирующая строка имеет длина 1 (исключая завершающий нулевой символ).

В вашем случае строка "\\n" имеет длина 2 (снова исключая завершающий ноль)) и содержит \ и n.

Вам необходимо отсканировать строку и при обнаружении \ проверить следующий символ.если это одно из допустимых выходов, вы должны заменить их на соответствующий символ, в противном случае пропустите или оставьте их обоих как есть.

(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;
}
4 голосов
/ 10 апреля 2011

Вы можете сделать это довольно легко, используя библиотеку алгоритма строки ускорения.Например:

#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;
}

Это, безусловно, не самый эффективный способ сделать это (поскольку он повторяет строку несколько раз), но он компактен и прост для понимания.

Обновление : Как указал ybungalobill, эта реализация будет неправильной, всякий раз, когда замещающая строка создает последовательность символов, которую ищет более поздняя замена или когда замена удаляет / изменяет последовательность символов, которую следует заменить.

Примером первого случая является "\\\\n" -> "\\n" -> "\n".Когда вы ставите замену "\\\\" -> "\\" последней (что на первый взгляд кажется решением), вы получаете пример для последнего случая "\\\\n" -> "\\\n".Очевидно, что не существует простого решения этой проблемы, что делает эту технику выполнимой только для очень простых escape-последовательностей.

Если вам нужно общее (и более эффективное) решение, вы должны реализовать конечный автомат, который выполняет итерацию строки, как предложено давкой.

1 голос
/ 10 апреля 2011

Я уверен, что есть, написанное кем-то, но это настолько тривиально, что я сомневаюсь, что это было специально опубликовано где-либо.алгоритмы в стандартной библиотеке.

0 голосов
/ 03 марта 2017

Вот симпатичный способ сделать это на платформах Unixy.

Вызывает команду операционной системы echo для преобразования.

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;
   }
0 голосов
/ 10 апреля 2011

Рассматривали ли вы использование printf?(или один из его родственников)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...