打印带有特殊字符的字符串变量

Print a string variable with its special characters

本文关键字:字符串 变量 特殊字符 打印      更新时间:2023-10-16

当我想在字符串中使用特殊字符时,我应该使用"":

std::string text("item t new_itemn")

但是,如果我输出这个字符串,显然,它会输出:

item      new_item

是否有办法设置std::cout来打印所有的特殊字符:

item t new_item n

tn将分别打印一个制表符(4个空格)和一个新行。

如果要输出tn。您必须在tn之前添加一个额外的作为前缀。

std::string text("item \t new_item \n")

没有内置的方法可以做到这一点。您需要手动转义字符。例如,在C中,它应该是这样的:

for (const char* p = text; *p != ''; ++p)
{
    int c = (unsigned char) *p;
    switch (c)
    {
        case '':
            printf("\\");
            break;
        case 'n':
            printf("\n");
            break;
        case 'r':
            printf("\r");
            break;
        case 't':
            printf("\t");
            break;
        // TODO: Add other C character escapes here.  See:
        // <https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences>
        default:
            if (isprint(c))
            {
                putchar(c);
            }
            else
            {
                printf("\x%X", c);
            }
            break;
    }
}

(注意,我写上述答案时,问题仍然带有C标记,我使用printf,因为我发现它比使用c++的iostream格式化机制更简单(特别是用于演示目的)。)

c++标准库不直接支持转义字符串。

您可以相当直接地实现它,但这会遇到三个问题:

  • 对于ASCII的转义字符(代码27)有非标准的转义,例如e,由例如g++支持。

  • 每个char (CHAR_BIT来自<limits.h>)的比特数,以及数字转义中必要的位数,与系统有关。

  • 字符是否可打印,即是否需要转义,取决于语言环境。当前语言环境的竞争指示器的数量使情况变得更加复杂:C级全局语言环境,c++级全局语言环境,或者例如cout ?

  • 中所包含的语言环境。

通过一些硬连线的选择,实现代码看起来像这样:

#include <stdio.h>                  // ::sprintf
#include <ctype.h>                  // ::isprint
#include <string>                   // std::string
#include <unordered_map>            // std::unordered_map
namespace my{
    using std::string;
    using std::unordered_map;
    auto string_from( char const ch )
        -> string
    { return string( 1, ch ); }     // Note: "string{1,ch}" is something else.
    auto is_printable( char const ch )
        -> bool
    { return !!::isprint( static_cast<unsigned char>( ch ) ); }
    auto escaped( char const ch )
        -> string
    {
        static unordered_map<char, string> const escapes =
        {
            { 'a', "\a" },        //  7, ^G, alert (bell)
            { 'b', "\b" },        //  8, ^H, backspace
            { 't', "\t" },        //  9, ^I, tab
            { 'n', "\n" },        // 10, ^J, newline / linefeed
            { 'v', "\v" },        // 11, ^K, vertical tab
            { 'f', "\f" },        // 12, ^L, formfeed
            { 'r', "\r" },        // 13, ^M, carriage return
            {   27, "\e" },        // 27, ^[, escape (NON-STANDARD)
            { '', "\\" }        // backslash
        };
        auto const it = escapes.find( ch );
        if( it != escapes.end() )
        {
            return it->second;
        }
        else if( is_printable( ch ) )
        {
            return string_from( ch );
        }
        else
        {
            int const code = static_cast<unsigned char>( ch );
            char buf[] = "\xDDDD";
            sprintf( buf + 2, "%04X", code );
            return buf;
        }
    }
    auto escaped( string const& s )
        -> string
    {
        string result;
        for( char const ch: s )
        {
            result += escaped( ch );
        }
        return result;
    }
}  // namespace my
#include <iostream>
#include <locale.h>
using namespace std;
auto main()
    -> int
{
    using my::escaped;
    auto const text = "item t xC7x81new_itemn"s;
    setlocale( LC_ALL, "" );
    cout << escaped( text ) << 'n';
}