我一次解析一个流一个字符,如下面的高度简化示例所示。我的问题是我需要将\\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 ;
}
答案 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;
}