将字符追加到 StringBuilder C++/CLI

Append Char To StringBuilder C++/CLI

我正在尝试使用 StringBuilder 创建通过串行端口发送的日志文件输出。输出存储在一个字节数组中,我正在递归它。

ref class UART_G {
   public:
     static array<System::Byte>^ message = nullptr;
     static uint8_t message_length = 0;
};

static void logSend ()
{
  StringBuilder^ outputsb = gcnew StringBuilder();
  outputsb->Append("Sent ");
  for (uint8_t i = 0; i < UART_G::message_length; i ++)
  {
    unsigned char mychar = UART_G::message[i];
    if (
      (mychar >= ' ' && mychar <= 'Z') || //Includes 0-9, A-Z.
      (mychar >= '^' && mychar <= '~') || //Includes a-z.
      (mychar >= 128 && mychar <= 254)) //I think these are okay.
    {
      outputsb->Append(L""+mychar);
    }
    else
    {
      outputsb->Append("[");
      outputsb->Append(mychar);
      outputsb->Append("]");
    }
  }
  log_line(outputsb->ToString());
}

我希望所有纯文本字符(例如 A、:)都作为文本发送,而功能字符(例如 BEL、NEWLINE)将像 [7][13] 一样发送。

发生的事情是,在所有情况下,StringBuilder 都将字符输出为数字。例如,A 被发送为 65。

例如,如果我的字节数组中有字符串 'APPLE' 和换行符,我想看到:

Sent APPLE[13]

相反,我看到:

Sent 6580807669[13]

我已经尝试了所有可以想象到的方法来让它正确显示字符,包括类型转换、将它连接到一个字符串、更改变量类型等...如果有人知道该怎么做,我将不胜感激这个。如果没有此功能,我的日志文件基本上无法读取。

您正在接收字符串的 ascii 值。

查看 Ascii 图表

 65 = A
 80 = P
 80 = P
 76 = L
 69 = E

写个ascii值转成字符串的函数就可以了

这是我想出的解决问题的代码:

static void logSend ()
{
  StringBuilder^ outputsb = gcnew StringBuilder();
  ASCIIEncoding^ ascii = gcnew ASCIIEncoding;
  outputsb->Append("Sent ");
  for (uint8_t i = 0; i < UART_G::message_length; i ++)
  {
    unsigned char mychar = UART_G::message[i];
    if (
      (mychar >= ' ' && mychar <= 'Z') || //Includes 0-9, A-Z.
      (mychar >= '^' && mychar <= '~') || //Includes a-z.
      (mychar >= 128 && mychar <= 254)) //I think these are okay.
    {
      outputsb->Append(ascii->GetString(UART_G::message, i, 1));
    }
    else
    {
      outputsb->Append("[");
      outputsb->Append(mychar);
      outputsb->Append("]");
    }
  }
  log_line(outputsb->ToString());
}

我仍然欣赏任何更有效或更易于阅读的替代方案。

您正在获取 ASCII 值,因为编译器正在选择 Append overloads that takes an integer of some sort. To fix this, you could do a explicit cast to System::Char, to force the correct overload 之一。

但是,这不一定会给出 128-255 的正确结果。您可以在从 ByteChar 的范围内输入一个值,它会给出 某些东西 ,但不一定是您所期望的。首先,0x80 到 0x9F 是控制字符,无论您从哪里获取字节,都可能不会像 Unicode 那样使用 0xA0 到 0xFF 的相同表示。

在我看来,最好的解决方案是对 0x80 到 0xFF 的其他控制字符也使用“[value]”语法。但是,如果您确实想将它们转换为字符,我会使用 Encoding::Default,而不是 Encoding::ASCII。 ASCII 只定义 0x00 到 0x7F,0x80 和更高的将出现为“?”。 Encoding::Default 是为您在 Windows 中选择的语言定义的任何代码页。

将所有这些结合起来,这就是您最终得到的结果:

for (uint8_t i = 0; i < UART_G::message_length; i ++)
{
  unsigned char mychar = UART_G::message[i];

  if (mychar >= ' ' && mychar <= '~' && mychar != '[' && mychar != ']')
  {
    // Use the character directly for all ASCII printable characters, 
    // except '[' and ']', because those have a special meaning, below.
    outputsb->Append((System::Char)(mychar));
  }
  else if (mychar >= 128)
  {
    // Non-ASCII characters, use the default encoding to convert to Unicode.
    outputsb->Append(Encoding::Default->GetChars(UART_G::message, i, 1));
  }
  else
  {
    // Unprintable characters, use the byte value in brackets.
    // Also do this for bracket characters, so there's no ambiguity 
    // what a bracket means in the logs. 
    outputsb->Append("[");
    outputsb->Append((unsigned int)mychar);
    outputsb->Append("]");
  }
}