【发布时间】:2010-12-07 13:52:13
【问题描述】:
如何在 C(++) 中将 "A\r\nB\tC\nD" 转换为 "A\\r\\nB\\tC\\nD"?
最好只使用标准库,并为纯 C 和纯 C++ 解决方案提供额外的支持。
【问题讨论】:
-
保存的原始字符串是什么?
\r/\n是例如字符(即 0x0D 和 0x0A)还是字符序列(即 \ 后跟 n)?
如何在 C(++) 中将 "A\r\nB\tC\nD" 转换为 "A\\r\\nB\\tC\\nD"?
最好只使用标准库,并为纯 C 和纯 C++ 解决方案提供额外的支持。
【问题讨论】:
\r/\n 是例如字符(即 0x0D 和 0x0A)还是字符序列(即 \ 后跟 n)?
当然,如果您使用的是宽字符串,请将@987654321@ 替换为wchar_t,将std::string 替换为std::wstring。
std::string input(/* ... */);
std::string output;
for(std::string::const_iterator it = input.begin(); it != input.end(); ++it)
{
char currentValue = *it;
switch (currentValue)
{
case L'\t':
output.append("\\t");
break;
case L'\\':
output.append("\\\\");
break;
//.... etc.
default:
output.push_back(currentValue);
}
}
您可以在 C 中执行此操作,但这会更加困难,因为您事先不知道缓冲区大小(尽管您可以在最坏的情况下猜测原始字符串大小的 2 倍)。即
//Disclaimer; it's been a while since I've written pure C, so this may
//have a bug or two.
const char * input = // ...;
size_t inputLen = strlen(input);
char * output = malloc(inputLen * 2);
const char * inputPtr = input;
char * outputPtr = output;
do
{
char currentValue = *inputPtr;
switch (currentValue)
{
case L'\t':
*outputPtr++ = '\\';
*outputPtr = 't';
break;
case L'\\':
*outputPtr++ = '\\';
*outputPtr = '\\';
break;
//.... etc.
default:
*outputPtr = currentValue;
}
} while (++outputPtr, *inputPtr++);
(记得在 C 版本中添加错误处理,例如 malloc 失败;))
【讨论】:
std::string,对吧?:))
这是我想出的……
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
inline char needs_escaping(char val) {
switch(val) {
case '\n': return 'n';
case '\r': return 'r';
case '\t': return 't';
}
return 0;
}
char *escape_string(char *in) {
unsigned int needed = 0, j = 0, length = strlen(in), i;
for(i = 0; i < length; i++) {
if(needs_escaping(in[i])) needed++;
}
char *out = malloc(length + needed + 1);
for(i = 0; i < length; i++) {
char escape_val = needs_escaping(in[i]);
if(escape_val) {
out[j++] = '\\';
out[j++] = escape_val;
}
else {
out[j++] = in[i];
}
}
out[length + needed] = '\0';
return out;
}
int main() {
char *in = "A\r\nB\tC\nD";
char *out = escape_string(in);
printf("%s\n", out);
free(out);
return 0;
}
【讨论】:
strlen 调用 - 对于类似的方法不需要订购 n 平方时间复杂度这个)。
我怀疑是否有任何标准库函数可以直接执行此操作。最有效的方法是简单地逐个字符地迭代输入缓冲区,有条件地复制到输出缓冲区,并使用一些特殊的状态机逻辑来处理 '\' 等。
我确信有多种方法可以通过 strchr() 等的各种组合来做到这一点,但在一般情况下它可能效率较低。
【讨论】:
我将创建一个包含 32 个 const char* 文字的查找表,每个控制代码(ASCII 0 到 ASCII 31)一个。然后,我将遍历原始字符串,将非控制字符(ASCII >= 32)复制到输出缓冲区,并将查找表中的值替换为 ASCII 0--31。
注意 1:ASCII 0 显然对于 C 字符串是特殊的(对于 C++ 则不是。)
注意 2:查找表将包含 C 转义序列,用于包含它们的代码(\n、\r 等)和反斜杠加上十六进制/八进制/十进制代码。
【讨论】:
这是 C# 中的一个算法。也许你可以把它当成伪代码,然后转换成 C++。
公共静态字符串 EscapeChars(字符串输入) { 字符串输出 = "";
foreach (char c in Input)
{
switch (c)
{
case '\n':
Output += "\\n";
break;
case '\r':
Output += "\\r";
break;
case '\t':
Output += "\\t";
break;
default:
Output += c;
break;
}
}
return Output;
}
【讨论】:
\n 不会被转换,因为\n 实际上在源字符串中没有斜杠。这会将“\\n”改为“\\\\n”。