C++ 可以打印罗马数字而不是整数吗?
我有一些打印一些小数字(实际上是年)的代码,要求打印数字,而不是使用通常的:C++ 可以打印罗马数字而不是整数吗?,c++,locale,iostream,roman-numerals,C++,Locale,Iostream,Roman Numerals,我有一些打印一些小数字(实际上是年)的代码,要求打印数字,而不是使用通常的: intmain(){ //做点什么使所有整数都以罗马数字出现 这个问题有两个独立的部分: 这个问题的枯燥部分是如何将int转换为一系列具有罗马表示值的字符 如何截取int的输出并将其转换为刚才描述的序列 罗马数字遵循一条相当直截了当的规则,这似乎最容易通过简单的查找表来处理。由于问题的主要焦点是如何使其与IOStreams一起工作,因此使用了一种直截了当的算法: template <typename To>
intmain(){
//做点什么使所有整数都以罗马数字出现
这个问题有两个独立的部分:
这个问题的枯燥部分是如何将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;
}
通过从std::num_put
派生并覆盖以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;
}
};
是一个显示具有不同对齐方式的两个不同值的实例。还实现了所有四个整数版本的do_put()
(即forlong
,long
,unsigned long
,和unsigned long
)。@chris我过去写过不同的方法(但最近没有)但是这一个完全是基于。你必须为无符号长
重载逐字逐句地写这整件事吗?@DietmarKühl,啊,我找了一点,发现了。我敢打赌我把它和我最近看到的一些完全不同的IO流代码混在一起了。很抱歉。@0x499602D2:如果你想的话还支持其他整数类型,您可能会使用基本逻辑创建一个内部版本,检查边界,并委托给内部版本。@0x499602D2:我已更新以覆盖所有相关的do_put()
的四个版本。
std::use_facet<std::num_put<cT>>(s.getloc())
.put(std::ostreambuf_iterator<char>(s), s, s.fill(), value);
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;
}
};
std::cout.imbue(std::locale(std::cout.getloc(), new num_put));
std::cout << "year " << 2013 << '\n';