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 之后的列未对齐)。如果你的可以正确显示每个字符,你应该看不到任何中断。
试试这个:
#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;
}
这会有点长,所以...工作代码在底部,它之前的所有内容都是解释。
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.
如果您愿意,您还可以修改此方法,让用户指定他们想要显示的列数。
间距:如果您传递 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()
。
如果宽度是常数,第一个将无法正确排列。这是因为 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::right
或 std::internal
,所以没有理由每次都传递 std::left
。
在某些平台上,字符 127 会破坏其后所有内容的格式,直到行尾;这是因为它实际上不是图形字符,因此实际上不会显示(Unicode 有 "DEL",而 Win32 控制台字体有一个房子,所以它们可以图形显示)。解决此问题的最简单方法是在 static_cast<char>(a)
.
之后输出一个或多个制表位或 \t
s
cout << /* output... */
<< static_cast<char>(a)
<< "\t\t"
<< /* output... */;
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)
.
所以我正在尝试编写这段代码,在完美的列中显示 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 之后的列未对齐)。如果你的可以正确显示每个字符,你应该看不到任何中断。
试试这个:
#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;
}
这会有点长,所以...工作代码在底部,它之前的所有内容都是解释。
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.
如果您愿意,您还可以修改此方法,让用户指定他们想要显示的列数。
间距:如果您传递
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()
。如果宽度是常数,第一个将无法正确排列。这是因为
之前使用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::right
或std::internal
,所以没有理由每次都传递std::left
。在某些平台上,字符 127 会破坏其后所有内容的格式,直到行尾;这是因为它实际上不是图形字符,因此实际上不会显示(Unicode 有 "DEL",而 Win32 控制台字体有一个房子,所以它们可以图形显示)。解决此问题的最简单方法是在
之后输出一个或多个制表位或static_cast<char>(a)
.\t
scout << /* output... */ << static_cast<char>(a) << "\t\t" << /* output... */;
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 miniatureif ... 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
。
- 在每 n 列之后有条件地在
因此,结合这些,我们得到如下所示的最终结果:
#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)
.