将“\\ n”转换为换行符

时间:2013-09-08 23:56:52

标签: c++

我一次解析一个流一个字符,如下面的高度简化示例所示。我的问题是我需要将\\n翻译成实际换行符(对于任何其他转义字符也是如此)。

有没有比我在这里完成的手动方式更好的方法?因为如果我必须以这种方式转换每个可能的转义字符,那就变得相当麻烦。

char c ;
std::stringstream s("foo \\n bar") ;

while (s.good()) {
    c = s.get() ;
    if (!s.good()) break ;
    if (c == '\\' && s.get() == 'n') c = '\n' ;
    std::cout << c ;
}

4 个答案:

答案 0 :(得分:4)

这样的事情:

int c;     // Not char.
while((c = s.get() != EOF)
{
    if (c == '\\')
    {
        switch(int escaped = s.get())
        {
           case 't':
              c = '\t';
              break;
           case 'n':
              c = '\n';
              break;
           case 'a':
              c = '\a';
           ...
           default:
              std::cout << c << escaped;    // Retain "invalid variants". 
              c = 0; 
              break;
        }
    }
    if (c)
    {
        std::cout << c;
    }
}

请注意,如果您需要COMPLETE解决方案,还需要处理\033\x1b\u0417(八进制或十六进制中的随机不可打印字符和unicode字符)

答案 1 :(得分:3)

你基本上是在写一个简单的词法分析器;通常的方法是使用状态机。

#include <iostream>
#include <stdexcept>
#include <sstream>
using namespace std;

int main() {
  char c;
  istringstream s("foo \\n bar");
  enum { CHARACTER, ESCAPE } state = CHARACTER;

  while (s.get(c)) {    
    switch (state) {
    case CHARACTER:
      if (c == '\\') {
        state = ESCAPE;
      } else {
        cout << c;
      }
      break;

    case ESCAPE:
      switch (c) {
      case 'n': cout << '\n'; break;
      case 't': cout << '\t'; break;
      default:
        throw runtime_error("unknown escape");
      }
      state = CHARACTER;
      break;
    }
  }
}

当然对于这个简单的例子,转义表可能是map<char, char>,但是如果你想支持更多的异类转义,例如\xNN其中NN是十六进制数字,那么它可以付钱来概括。

状态机方法的优点是一个位置可以读取字符。各个州只负责将该字符添加到输出中,看他们认为合适,并通过分配state变量转换到其他状态。

答案 2 :(得分:1)

你的代码基本上是正确的,但我觉得它根本不是特别麻烦。

但是你的代码有一个错误:如果你有这个输入:'\\', 'g'那么g' character will be lost because you don't preserve the data retrieved by your second s.get()`调用。

我就是这样做的:

bool escaped = false;
while (s.good()) {
    c = s.get() ;
    if (!s.good()) break ;
    if( escaped ) {
        if( c == 'n' ) {
            std::cout << '\n' ;
        } else {
            std::cout << '\\' << c;
        }
        escaped = false;
    } else {
        if( c == '\\' ) {
            escaped = true;
        } else {
            std::cout << c ;
        }
    }
}

答案 3 :(得分:0)

我不推荐它在C ++中使用,但这是我在20年左右在C中写的一些可能提供一些启发的代码。

#include <string.h>
#include <stdio.h>

char *translate(char *string)
{
      char *here=string;
      size_t len=strlen(string);
      int num;
      int numlen;

      while (NULL!=(here=strchr(here,'\\')))
      {
            numlen=1;
            switch (here[1])
            {
            case '\\':
                  break;

            case 'r':
                  *here = '\r';
                  break;

            case 'n':
                  *here = '\n';
                  break;

            case 't':
                  *here = '\t';
                  break;

            case 'v':
                  *here = '\v';
                  break;

            case 'a':
                  *here = '\a';
                  break;

            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
                  numlen = sscanf(here,"%o",&num);
                  *here = (char)num;
                  break;

            case 'x':
                  numlen = sscanf(here,"%x",&num);
                  *here = (char) num;
                  break;
            }
            num = here - string + numlen;
            here++;
            memmove(here,here+numlen,len-num );
      }
      return string;
}