【问题标题】:How to represent special characters using multiple ASCII characters如何使用多个 ASCII 字符表示特殊字符
【发布时间】:2020-08-28 07:40:19
【问题描述】:

我试图用各自的多字符 ASCII 表示法来表示特殊字符,例如 CR、LF、NULL 等。\r\n\0。

基本上,我想将包含这些特殊字符的字符串变量写入 ASCII 日志文本文件,这样我就可以从该文件中复制文本,将其粘贴到 Visual Studio 中以接收与之前相同的字符串变量写的。

我想最好的方法是用 Visual Studio 代码编辑器使用的相同格式编写特殊字符。 (请赐教如何调用字符串格式)。

示例代码:

string mystring = "\r\n\0\0\u0001\u0018\0\0\u0001\u000fXML";
Console.WriteLine(mystring);

所以我想转换 mystring 以便 Console.WriteLine 输出 \r\n\0\0\u0001\u0018\0\0\u0001\u000fXML 而不是:

控制台只是描述问题的一种简单方法。我将以不同的方式打印我的字符串,因此我需要将 mystring 转换为可以打印 \r\n\0\0\u0001\u0018\0\0\u0001\u000fXML 的字符串(以及所有其他特殊字符以相同的方式)。

【问题讨论】:

标签: c# parsing ascii special-characters data-representation


【解决方案1】:

这些被称为转义序列。您可以咨询the grammar 以查看需要在字符串文字中转义哪些字符。基本上,您可以使用其 Unicode 字符转义序列来转义任何字符。

\u hex_digit hex_digit hex_digit hex_digit

例如:将 U+000D 替换为 \u000d 作为回车符。

如果你想保持字符串简短,那么有些不需要需要转义。 确实需要转义的是:

  • " (U+0022)
  • \ (U+005C)
  • 回车符 (U+000D)
  • 换行符 (U+000A)
  • 下一行字符 (U+0085)
  • 行分隔符 (U+2028)
  • 段落分隔符 (U+2029)

其他所有内容都可以按字面意思插入。

如果您还只想允许对源文件进行 ASCII 编码,那么您可以更加严格地限制字面表示的字符。您可能想要非常严格。

让自己成为一个函数来决定一个字符是否应该被转义。您可能希望从以下函数开始:

public static bool IsSafeForLiteral(char ch) =>
    ch < 127
    && ch != '\u0022' // double quote
    && ch != '\u005c' // backslash
    && ch != '\u000d' // carriage return
    && ch != '\u000a' // line feed
    && (
        Char.IsLetterOrDigit(ch)
        || Char.IsPunctuation(ch)
        || Char.IsSymbol(ch)
        || (ch == ' ')
    );

然后使用此测试构造一个函数,将字符串转换为字符串文字的 C# 源代码。

public static string ToSourceStringLiteral(string str)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("\"");
    foreach (char c in str) {
        if (IsSafeForLiteral(c)) {
            sb.Append(c);
        } else {
            sb.AppendFormat(@"\u{0:X4}", (int)c);
        }
    }
    sb.Append("\"");
    return sb.ToString();
}

如果您真的很喜欢将回车显示为 \r 而不是 \u000d,那么您还必须编写所有这些转义序列。

一种方法是制作一个字符字典来替换并应用它。

public static Dictionary<char, string> CSharpSpecialEscapes = new Dictionary<char, string>() {
    { '\u0000', @"\0" },
    { '\u0007', @"\a" },
    { '\u0008', @"\b" },
    { '\u0009', @"\t" },
    { '\u000a', @"\n" },
    { '\u000b', @"\v" },
    { '\u000c', @"\f" },
    { '\u000d', @"\r" },
    { '\u001b', @"\e" },
    { '\u005c', @"\\" }
};

public static string ToSourceStringLiteral(this string str)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("\"");
    foreach (char c in str) {
        if (CSharpSpecialEscapes.TryGetValue(c, out string replacement)) {
            sb.Append(replacement);
        } else if (IsSafeForLiteral(c)) {
            sb.Append(c);
        } else {
            sb.AppendFormat(@"\u{0:X4}", (int)c);
        }
    }
    sb.Append("\"");
    return sb.ToString();
}

根据性能要求,您还可以使用 0..127 范围内的所有替换项预先填充一个数组并直接使用它,尽管此时源代码开始看起来不太可维护。我推荐我上面写的内容,因为它是描述性的(与字符串转义序列的定义方式相匹配,而不是最佳效率)。

我还让这个版本在开头和结尾添加了引号。如果您不想要 sb.Append("\""); 行,您可以轻松删除它们。

【讨论】:

  • 哇......我希望微软实际上有一个内置的方法,因为它们在 Visual Studio 变量预览中以这种方式表示字符串......
  • 哦,罗斯林某处可能有办法。 ;) 我并不是说没有东西已经存在——这只是手动操作的方法。我希望有人会发布更好的东西。但与此同时,这确实工作,并且是可定制和可理解的。
【解决方案2】:

您可以在引号前使用“@”符号。

string mystring = @"\r\n\0\0\u0001\u0018\0\0\u0001\u000fXML";

这可以防止使用反斜杠 \ 转义

编辑:

或者只是使用双反斜杠来转义反斜杠本身。

string mystring = "\\r\\n\\0\\0\\u0001\\u0018\\0\\0\\u0001\\u000fXML";

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    相关资源
    最近更新 更多