将具有显式转义序列的字符串转换为相对字符

Mic*_*lis 11 c++ escaping

我需要一个函数将"显式"转义序列转换为相对不可打印的字符.ES:

char str[] = "\\n";
cout << "Line1" << convert_esc(str) << "Line2" << endl:
Run Code Online (Sandbox Code Playgroud)

会给出这个输出:

Line1

Line2
Run Code Online (Sandbox Code Playgroud)

有没有这样做的功能?

dav*_*vka 14

我认为你必须自己编写这样的函数,因为转义字符是编译时的特性,即当你编写"\n"编译器时会用\neol字符替换序列.结果字符串的长度为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;
}
Run Code Online (Sandbox Code Playgroud)

  • “太简单了”:从来都不简单。当您重新发明轮子时,几乎总是打破规范化。规格中总是有晦涩的特征。例如,您将如何处理\ u unicode序列或特定于IO / OS的\ n,它们可能会被OS劫持,尤其是在文本模式下的文件流中... (2认同)

oll*_*llb 5

你可以很容易地做到这一点,使用 boost 字符串算法库。例如:

#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;
}
Run Code Online (Sandbox Code Playgroud)

这肯定不是执行此操作的最有效方法(因为它多次迭代字符串),但它紧凑且易于理解。

更新:正如 ybungalobill 所指出的,这个实现将是错误的,每当替换字符串产生一个字符序列时,以后的替换正在搜索,或者当替换删除/修改一个应该被替换的字符序列时。

第一种情况的示例是"\\\\n"-> "\\n"-> "\n"。当您将"\\\\"->"\\"替换放在最后(乍一看似乎是解决方案)时,您会得到后一种情况的示例"\\\\n"-> "\\\n"。显然,这个问题没有简单的解决方案,这使得该技术仅适用于非常简单的转义序列。

如果您需要一个通用(且更高效)的解决方案,您应该实现一个迭代字符串的状态机,如 davka 所建议的。

  • 这是完全错误的。`escape("\\\\t")` 将返回 `"\t"` 而不是 `"\\t"`。 (2认同)