【问题标题】:Convert string with explicit escape sequence into relative character将具有显式转义序列的字符串转换为相对字符
【发布时间】:2011-08-02 12:02:16
【问题描述】:

我需要一个函数来将“显式”转义序列转换为相关的不可打印字符。 乙:

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

会给出这个输出:

Line1

Line2

有没有这样的功能?

【问题讨论】:

    标签: c++ escaping


    【解决方案1】:

    这是在 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;
       }
    

    【讨论】:

    • 您可以类似地通过生成一个小 C++ 程序来打印字符串、编译并运行它来做到这一点。不过,这种方法可能有点重。
    【解决方案2】:

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

    #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" 的示例。显然,这个问题没有简单的解决方案,这使得这种技术只适用于非常简单的转义序列。

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

    【讨论】:

    • 这是完全错误的。 escape("\\\\t") 将返回 "\t" 而不是 "\\t"
    • @ybungalobill 感谢您的评论。我已经更新了答案,因此它也指出了该技术的局限性。
    • \x 呢?
    【解决方案3】:

    我认为你必须自己编写这样的函数,因为转义字符是编译时特性,即当你编写"\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;
    }
    

    【讨论】:

    • 事实上,我想知道该函数是否已经编写好了。
    • @Glaedr:我相信它已经被写了数百次了,但是它太简单了,不能花太多时间去寻找。我会做一个快速的谷歌搜索,如果我没有马上找到,我会自己写,这是一个很好的练习。如果将结果复制到新字符串中,则更简单,因为您不需要缩小原始字符串,并且可以接受 const 输入
    • 好的,我设置了一个类似上面的函数,一切正常,谢谢!
    • "这太简单了":它从来都不是简单的。当您重新发明轮子时,您几乎总是会破坏规范化。规范中总是有一些晦涩难懂的特征。例如,您将如何处理 \u unicode 序列,或可能被操作系统劫持的 IO/OS 特定 \n,尤其是在文本模式下的文件流中...
    【解决方案4】:

    我确定有人写过,但它太琐碎了,我怀疑它是否在任何地方专门发布过。

    只需使用标准库中的各种“查找”/“替换”式算法自己重新创建即可。

    【讨论】:

      【解决方案5】:

      你考虑过使用 printf 吗? (或其亲属之一)

      【讨论】:

      • 您将如何使用printf 来执行此操作?
      • 我认为 printf 不能这样做,因为转义序列的替换是由编译器完成的,而不是由 printf 完成的。
      • @Gnafoo:实际上它是预处理器,如果你在谈论字符串文字的话。但这仍然与问题完全无关,涉及将字符串{'\\', 'n'} 转换为字符串{'\n'}
      猜你喜欢
      • 1970-01-01
      • 2020-03-15
      • 2011-04-01
      • 2012-02-02
      • 1970-01-01
      • 2022-11-10
      • 1970-01-01
      • 1970-01-01
      • 2013-01-29
      相关资源
      最近更新 更多