C++专栏,完美排列

C++ columns, line up perfectly

所以我正在尝试编写这段代码,在完美的列中显示 ASCII 代码,但这些列是完美排列的。我做错了什么?

#include <iostream>   // cout
#include <iomanip>    // setw

using namespace std;
int main ()
{
    int a;                                                                    
    for(a=32;a<=255;++a)
    {
        cout << a << setw(2) <<static_cast<char>(a)<< setw(20);              
    }

    return 0;
}

这就是我想要的样子, http://www.asciitable.com/index/extend.gif

我认为您正在寻找这样的东西:

#include <iostream>   // cout
#include <iomanip>    // setw

using namespace std;
int main ()
{
    int a;                                                                    
    for(a=32;a<=255;++a)
    {
        cout << setw(3) << a << setw(20) <<static_cast<char>(a) << std::endl;              
    }

    return 0;
}

setw(3) 出现在字符之前,您想要 3 而不是评论中提到的 2。 而且你还忘了在最后打印一个换行符。

要获得看起来像 link 的东西,您可以这样做:

#include <iostream>   // cout
#include <iomanip>    // setw

using namespace std;
int main ()
{
    int a;
    int nColumns = 14;
    for(a=32;a<=255;++a)
    {
        cout << setw(10) << a << setw(8) <<static_cast<char>(a);
        if((a-31)%nColumns == 0)
        {
            cout<<endl;    
        }
    }
    return 0;
}

我的在线编译器不显示从 130 到 255 的字符,因此出现了一个中断(130 之后的列未对齐)。如果你的可以正确显示每个字符,你应该看不到任何中断。

Example

试试这个:

#include <iostream>   // cout
#include <iomanip>    // setw

using namespace std;
int main()
{
    int a;
    int count = 0;
    for (a = 32; a <= 255; ++a)
    {
        cout << a << setw(2) << static_cast<char>(a);
        if (count != 3)
        {
            cout << setw(20);
            count++;
        }
        else
        {
            count = 0;
            cout << endl;
        }
    }
    cout << endl;

    return 0;
}

PS:如果你想有更多的列同样长尝试改变这个 if (count != 3) 和这个 cout << setw(20);if (count != 6)cout << setw(9);

正如之前在评论中提到的,你需要在输出值之前询问std::cout正确的宽度,并且你需要有一种输出新行的方法,当你有一定数量的列。所以这只是对您的代码的一个小修改(这将使行中的数字增加,如果您希望值在一列而不是一行中增加,您需要做更多的数学运算或者直接输出值,将它们附加到每一行的字符串,然后在末尾输出值。我将第一个解决方案添加到这个答案的末尾,因为行增量答案已经由其他人给出:-)):

#include <iostream>
#include <iomanip>

using namespace std;
int main ()
{
    int nocols = 5;    // number of columns that you want
    for (int a = 32; a < 256; ++a)
    {
        cout << setw(3) << a << setw(20) << static_cast<char>(a);
        if (!((a - 31) % nocols))
            cout << endl;
    }

    return 0;
}

这是一种列增量格式:

int nocols = 8;    // number of columns that you want
int norows = 1 + (256 - 32 - 1) / nocols; // number of rows

for (int row = 0; row < norows; ++row)
{
    for (int col = 0; col < nocols; ++col)
    {
        int ch = 32 + norows * col + row;
        if (ch < 256)
            cout << setw(3) << ch << setw(10) << static_cast<char>(ch) << ' ';
    }
    cout << endl;
}

这会有点长,所以...工作代码在底部,它之前的所有内容都是解释。

  1. Columns:在同一行中包含 n 列的一种简单方法是有条件地在之后插入换行符每 n 个条目。最简单的方法是使用模运算,将第一个条目视为 1 并检查除以 n 时的余数是否为 0.

        const int NUMBER_OF_COLUMNS = 5;
    
        // ...
    
        for(a=32;a<=255;++a)
        {
            cout << /* output... */
                 << ((a - 31) % NUMBER_OF_COLUMNS == 0 ? "\n" : "");
        }
    

    这是如何工作的:我们对循环进行加法或减法,将其视为从 1 开始(在本例中,通过减去 31,因为它从 32 开始),然后对该值使用模数来确定它是否是可以被 n 整除。如果是,我们插入 "\n"(换行符);如果不是,我们插入 ""(无)。

    这也可以修改为始终在循环结束时输出换行符,而不将 cout << endl;cout << '\n'; 放在循环之外。

    // Change...
    << ((a - 31) % NUMBER_OF_COLUMNS == 0 ? "\n" : "");
    // To...
    << ((a - 31) % NUMBER_OF_COLUMNS == 0 || a == 255 ? "\n" : "");
    // Inserts "\n" every n columns, OR when a is 255.
    

    或者,您可以将检查放在输出的开头,并将循环的计数器视为从 0 开始;在这种情况下,我们将减去 32.

        const int NUMBER_OF_COLUMNS = 5;
    
        // ...
    
        for(a=32;a<=255;++a)
        {
            cout << ((a - 32) % NUMBER_OF_COLUMNS == 0 ? "\n" : "")
                 << /* output... */;
        }
    

    这将在输出的最开头放置一个换行符,尽管如果不需要,可以通过专门检查 a 实际上不是它的起始值来避免。

    // Change...
    ((a - 32) % NUMBER_OF_COLUMNS == 0 ? "\n" : "")
    // To...
    ((a - 32) % NUMBER_OF_COLUMNS == 0 && a != 32 ? "\n" : "")
    // Inserts "\n" every n columns, unless a is 32.
    

    如果您愿意,您还可以修改此方法,让用户指定他们想要显示的列数。

  2. 间距:如果您传递 std::setw() 一个常量值,它可能会在某些地方弄乱您的格式。就目前而言,间距有两个问题。

    for(a=32;a<=255;++a)
    {
        cout << a
             << setw(2)   // Doesn't take into account the number of digits in a.
             <<static_cast<char>(a)
             << setw(20); // Doesn't take into account character 127 not being a graphical
                          //  character.
    }
    

    作为替代方案,您可以使用 \t 输出制表符,更改应用 std::setw() 的输出,或使用一些逻辑来确定要传递的值 std::setw()

    1. 如果宽度是常数,第一个将无法正确排列。这是因为 std::setw() 会影响它之后的下一个输出,并且强制转换为 char 可以保证此输出始终恰好是一个字符(因此,如果您指定宽度 x,它将用 x - 1 个空格填充)。有两种方法可以解决这个问题:在输出 a...

      之前使用 std::setw()std::left
      cout << setw(4) << left // Tells cout to make sure a is at least 4 characters,
                              //  padding it at the end if necessary.
                              // 4 characters are used to account for 3 digits + a space.
           << a
           << /* output... */;
      

      或者将 std::setw() 应用到 static_cast<char>(a),就像你现在一样,但是使用一点逻辑来确定值...

      cout << a
           << setw(a < 100 ? 3 : 2)           // Set width to 3 if a < 100, or 2 otherwise.
           << static_cast<char>(a)
           << /* output... */;
      

      如果我们使用第一个,将 std::left 移到循环外可能会更好,如下所示:

      cout << left;
      for(a=32;a<=255;++a)
      {
          cout << setw(4)
               << /* output.. */;
      }
      cout << right; // Reset to default.
      

      因为我们没有在循环中传递 std::rightstd::internal,所以没有理由每次都传递 std::left

    2. 在某些平台上,字符 127 会破坏其后所有内容的格式,直到行尾;这是因为它实际上不是图形字符,因此实际上不会显示(Unicode 有 "DEL",而 Win32 控制台字体有一个房子,所以它们可以图形显示)。解决此问题的最简单方法是在 static_cast<char>(a).

      之后输出一个或多个制表位或 \ts
      cout << /* output... */
           << static_cast<char>(a)
           << "\t\t"
           << /* output... */;
      
  3. Wait, what's that ?: thing?: That would be the conditional operator, unofficially known as the "ternary operator". This operator takes 3 operands, and acts like a miniature if ... else statement that can be used as an expression。它用作:

    条件 ? 真结果 : 假结果

    condition 转换为 bool,并且可以是任何可以计算为布尔值的值。如果 true,运算符的计算结果为 true-result;如果 false,它的计算结果为 false-result。这个运算符看起来有点奇怪,但非常有用,因为它允许在无法使用 if 语句的情况下(例如在变量赋值期间)应用条件逻辑。

    这里,我用了两次:

    • 在每 n 列之后有条件地在 std::cout 中插入一个换行符。请注意,它被括在括号中;这是因为 it has lower precedence than the << operator。它的计算结果为 "\n" 或空字符串 "",具体取决于 a.
    • 的值
    • 确定要传递给 std::setw() 的值,如果它应用于 static_cast<char>(a) 而不是 a。如果 a 小于 100,则计算结果为 3,否则为 2

因此,结合这些,我们得到如下所示的最终结果:

#include <iostream>   // cout
#include <iomanip>    // setw, left, right

using namespace std;
int main ()
{
    const int NUMBER_OF_COLUMNS = 8; // Number of columns per line.

    cout << left; // Append padding after output.
    int a;
    for(a=32;a<=255;++a)
    {
        cout << setw(4)                         // Pad until 4 characters.
             << a
             << static_cast<char>(a)
             << "\t\t"                          // Use tabs for spacing.
             << ((a - 31) % NUMBER_OF_COLUMNS == 0 || a == 255 ? "\n" : "");
               // Insert newline when specified, and after outputting the last entry.
    }
    // This isn't necessary since you exit right after, but it's a useful habit to develop
    //  if you format text for console output frequently.
    // Remove if desired.
    cout << right; // Reset to default.

    return 0;
}

我还建议:
1) 将 using namespace std; 移动到 main() 本身,and/or 将其替换为:
using std::cout; using std::left; using std::right; using std::setw;
2) 在 for 循环条件中声明 a,如 for(int a=32;a<=255;++1).