罗马数字可以打印而不是int吗
Can Roman Numerals be printed instead of an int?
我有一些代码可以打印一些小数字(实际上是年份),要求将数字打印为罗马数字,而不是使用通常的印度-阿拉伯数字:
int main() {
// do something to make all integers appear in Roman numerals
std::cout << "In the year " << 2013 << " the following output was generated:n";
// ...
}
如何将int
格式化为罗马数字?
这个问题有两个独立的部分:
- 问题的无聊部分是如何将
int
转换为具有罗马表示值的字符序列 - 如何截取
int
的输出并将其转换为刚才描述的序列
罗马数字遵循一条相当直接的规则,这似乎是用简单的查找表最容易处理的。由于问题的主要焦点是如何使其与IOStreams一起工作,因此使用了一种直接的算法:
template <typename To>
To make_roman(int value, To to) {
if (value < 1 || 3999 < value) {
throw std::range_error("int out of range for a Roman numeral");
}
static std::string const digits[4][10] = {
{ "", "M", "MM", "MMM", "", "", "", "", "", "" },
{ "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" },
{ "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" },
{ "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" },
};
for (int i(0), factor(1000); i != 4; ++i, factor /= 10) {
std::string const& s(digits[i][(value / factor) % 10]);
to = std::copy(s.begin(), s.end(), to);
}
return to;
}
每个"数字"都是通过查找相应的字符串并将其复制到迭代器中生成的。如果整数超出了可以使用罗马数字表示的值的范围,则引发异常。可以生成的最长字符串为15个字符长(3888)。
下一步是设置std::cout
,使其使用上述转换格式化int
。当std::ostream
需要转换任何内置的数字类型(整数、浮点)或类型bool
和void const*
时,它从流的std::locale
中获得std::num_put<cT>
方面,并在对象上调用put()
,本质上使用
std::use_facet<std::num_put<cT>>(s.getloc())
.put(std::ostreambuf_iterator<char>(s), s, s.fill(), value);
通过从std::num_put<char>
派生并覆盖以long
为自变量的版本的do_put()
成员函数,可以更改数字的格式:
class num_put
: public std::num_put<char>
{
iter_type do_put(iter_type to, std::ios_base& fmt, char fill, long v) const {
char buffer[16];
char* end(make_roman(v, buffer));
std::streamsize len(end - buffer);
std::streamsize width(std::max(fmt.width(0), len));
std::streamsize fc(width - (end - buffer));
switch (fmt.flags() & std::ios_base::adjustfield) {
default:
case std::ios_base::left:
to = std::copy(buffer, end, to);
to = std::fill_n(to, fc, fill);
break;
case std::ios_base::right:
case std::ios_base::internal:
to = std::fill_n(to, fc, fill);
to = std::copy(buffer, end, to);
}
return to;
}
};
虽然这个功能比较长,但它是相当直接的:
- 值
v
被转换为罗马数字的字符串,并存储在buffer
中 - 结果字符串的长度和要产生的字符数被确定(并且流的
width()
被重置为0
) - 根据输出的对齐位置,要么复制值,然后存储填充字符(如果有的话),要么反过来
剩下的就是使用此版本的std::num_put<char>
面创建一个std::locale
,并将生成的std::locale
安装到std::cout
:中
std::cout.imbue(std::locale(std::cout.getloc(), new num_put));
std::cout << "year " << 2013 << 'n';
下面是一个实际示例,显示了具有不同对齐方式的几个不同值。该示例还实现了do_put()
的所有四个整数版本(即,用于long
、long long
、unsigned long
和unsigned long long
)。
相关文章:
- 必须首先打印向量 v1 中最接近整数 x 的数字<int>
- c++:如何打印出一个强制转换的 int 值?
- 打印"矢量<对<int,int>>"
- C++:根据int值的基数使用条件格式打印
- 当我们声明 cin 为 int 并从 cin 中获取输入并在 cout 中打印 cin 时会发生什么?
- 将char类型指定给int以打印相应的ASCII字符
- "1L << count"是什么意思?如何使用超出"unsigned long long int? "范围的语句编号打印?
- 打印一个带有静态 int 的函数,有一个 std::cout 和多个 std::cout 有什么区别?
- 是否打印指向已定义 int 的成员指针
- 当我输入一个字母时,cin 输入(输入是一个 int),而不是打印错误一次,它打印正确一次,然后在循环的其余部分打印 i
- uint8_t在转换为无符号 int 时未打印正确的值
- 如何在<int> c++ 中将矢量打印到终端
- 如何在C++中打印矢量<map<string,int> >
- 我如何转换一个基于动态的,基于指针的int堆栈,以便将其打印成字符串
- 随机打印出int的大小,不知道为什么
- 从指针打印动态int阵列中获取怪异的字符
- 为什么打印新的int[]会给我一个C ++的地址
- 我的 c++ 程序不打印任何字符,但是如果我将它们更改为 int,代码可以完美运行
- 在 int 数组中打印出位
- C++。为什么 std::cout << char + int 打印 int 值?