我是c +的新手,虽然我对Java有基本的了解,但我正在尝试制作一个转换罗马数字输入的程序,然后找到等效的阿拉伯数字并输出它。但是我有一个问题是在罗马数字中找到特定的前缀我正在尝试使用str.find函数,然后使用str.substr来测试前缀是否存在,如果是,它给出了阿拉伯语值,并且然后将继续下一个前缀。但是我的代码似乎失败或打印出“0”。我想知道我是否使用str函数错误,或者是否有更简单的方法在字符串中查找前缀?
这是我目前的代码:
#include <cstdlib>
#include <iostream>
#include <cctype>
using namespace std;
/*
*
*/
int main() {
string roman_digits [] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
string roman_tens [] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
string roman_hundreds [] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
string roman_thousands [] = {"", "M", "MM", "MMM"};
string line, substr;
int arabic = 0;
// MCCCXXXVII
cout << "Type in a Roman numeral: ";
// Loops through inputted Roman Numerals.
while (cin >> line) {
if (!cin.eof()) {
int i = 0;
// Loops through a Roman numeral and changes it to uppercase.
while (line[i]) {
char c;
c = line[i];
c = (toupper(c));
line[i] = c;
i++;
}
// Loops through checking roman numeral with the thousands array and if there is a match prints out the equivalent arabic number.
for (int i = 0; i < 4; i++) {
if (line.find("MMM") != string::npos) {
unsigned pos = line.find("MMM");
substr = line.substr(pos, 3);
line.erase(pos, 3);
} else if (line.find("MM") != string::npos) {
unsigned pos = line.find("MM");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("M") != string::npos) {
unsigned pos = line.find("M");
substr = line.substr(pos, 1);
line.erase(pos, 1);
}
if (roman_thousands[i] == substr){
arabic = arabic + (i * 1000);
}
}
// Loops through checking roman numeral with the hundreds array and if there is a match prints out the equivalent arabic number.
for (int i = 0; i < 10; i++) {
if (line.find("CM") != string::npos){
unsigned pos = line.find("CM");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("DCCC") != string::npos){
unsigned pos = line.find("DCCC");
substr = line.substr(pos, 4);
line.erase(pos, 4);
} else if (line.find("DCC") != string::npos){
unsigned pos = line.find("DCC");
substr = line.substr(pos, 3);
line.erase(pos, 3);
} else if (line.find("DC") != string::npos){
unsigned pos = line.find("DC");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("D") != string::npos){
unsigned pos = line.find("D");
substr = line.substr(pos, 1);
line.erase(pos, 1);
} else if (line.find("CD") != string::npos){
unsigned pos = line.find("CD");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("CCC") != string::npos){
unsigned pos = line.find("CCC");
substr = line.substr(pos, 3);
line.erase(pos, 3);
}else if (line.find("CC") != string::npos){
unsigned pos = line.find("CC");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("C") != string::npos){
unsigned pos = line.find("C");
substr = line.substr(pos, 1);
line.erase(pos, 1);
}
if (roman_hundreds[i] == substr) {
arabic = arabic + (i * 100);
}
}
// Loops through checking roman numeral with the tens array and if there is a match prints out the equivalent arabic number.
for (int i = 0; i < 10; i++) {
if (line.find("XC") != string::npos){
unsigned pos = line.find("XC");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("LXXX") != string::npos){
unsigned pos = line.find("LXXX");
substr = line.substr(pos, 4);
line.erase(pos, 4);
}else if (line.find("LXX") != string::npos){
unsigned pos = line.find("LXX");
substr = line.substr(pos, 3);
line.erase(pos, 3);
} else if (line.find("LX") != string::npos){
unsigned pos = line.find("LX");
substr = line.substr(pos, 2);
line.erase(pos, 2);
}else if (line.find("L") != string::npos){
unsigned pos = line.find("L");
substr = line.substr(pos, 1);
line.erase(pos, 1);
}else if (line.find("XL") != string::npos){
unsigned pos = line.find("XL");
substr = line.substr(pos, 2);
line.erase(pos, 2);
}else if (line.find("XXX") != string::npos){
unsigned pos = line.find("XXX");
substr = line.substr(pos, 3);
line.erase(pos, 3);
}else if (line.find("XX") != string::npos){
unsigned pos = line.find("XX");
substr = line.substr(pos, 2);
line.erase(pos, 2);
}else if (line.find("X") != string::npos){
unsigned pos = line.find("X");
substr = line.substr(pos, 1);
line.erase(pos, 1);
}
if (roman_tens[i] == substr) {
arabic = arabic + (i * 10);
}
}
// Loops through checking roman numeral with the digits array and if there is a match prints out the equivalent arabic number.
for (int i = 0; i < 10; i++) {
if (line.find("IX") != string::npos){
unsigned pos = line.find("IX");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("VIII") != string::npos){
unsigned pos = line.find("VIII");
substr = line.substr(pos, 4);
line.erase(pos, 4);
} else if (line.find("VII") != string::npos){
unsigned pos = line.find("VII");
substr = line.substr(pos, 3);
line.erase(pos, 3);
} else if (line.find("VI") != string::npos){
unsigned pos = line.find("VI");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("V") != string::npos){
unsigned pos = line.find("V");
substr = line.substr(pos, 1);
line.erase(pos, 1);
} else if (line.find("IV") != string::npos){
unsigned pos = line.find("IV");
substr = line.substr(pos, 2);
line.erase(pos, 2);
} else if (line.find("III") != string::npos){
unsigned pos = line.find("III");
substr = line.substr(pos, 3);
line.erase(pos, 3);
} else if (line.find("II") != string::npos){
unsigned pos = line.find("II");
substr = line.substr(pos, 2);
line.erase(pos, 2);
}else if (line.find("I") != string::npos){
unsigned pos = line.find("I");
substr = line.substr(pos, 1);
}
if (roman_digits[i] == substr) {
arabic = arabic + i;
}
}
cout << "The Arabic equivalent of " << line << " is: " << arabic << endl;
arabic = 0;
} else {
cout << "Invalid Roman numeral." << endl;
}
}
return 0;
}
非常感谢任何帮助。
编辑:所以我接受了建议,似乎一切正常(代码已被编辑),所以非常感谢。 ^^但是,由于它单独检查“X”并删除它,我的程序将输入“IX”翻译为11,当它实际为9.我知道这与我的程序找到前缀的顺序有关字符串,但我不知道如何解决它,所以任何帮助都会很好。
再次感谢
答案 0 :(得分:1)
std::string::find()
函数不返回布尔值,而是返回找到的子字符串的位置,如果没有这样的位置,则返回std::string::npos
。因此,您的测试可能应该如下所示:
if (line.find("MMM") != std::string::npos) { ... }
当然,尝试相同的测试序列四次并没有多大意义。您可能希望索引i
从千位数组中选择适当的字符串,并且只进行一次测试。当然,您可能希望颠倒字符串的顺序或向下计数以使其有用。
对于其他检查,您可能应该使用find()
以及可能还有其他数字。
答案 1 :(得分:1)
string::find
不返回bool(如下一行所示)。如果找不到该字符串,则返回一个特殊常量string::npos
。值为0表示在开头找到字符串,而不是失败。
试试这个
string::size_type pos = line.find("MMM");
if (pos != string::npos)
{
...
}
其他评论
这是将字符串转换为大写的单行方式。您需要加入<algorithm>
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
您可以创建诸如roman_digits const string
之类的数据阵列,以防止意外修改它们。
尽量将变量声明为尽可能接近第一次使用。例如,只需要在while循环中定义char c
。
答案 2 :(得分:1)
我认为这段代码更简单,我没有实现错误检查,但它应该不难:
#include <iostream>
#include <map>
using namespace std;
int fromRoman(string n)
{
map<char, int> m;
m['I'] = 1;
m['V'] = 5;
m['X'] = 10;
m['L'] = 50;
m['C'] = 100;
m['D'] = 500;
m['M'] = 1000;
int tmp = 0;
int res = 0;
for (string::iterator i = n.begin(); i != n.end(); ++i)
{
int d = m[*i];
if (d < tmp)
{
res += tmp;
tmp = d;
}
else if (d > tmp)
{
if (tmp == 0)
tmp = d;
else
{
res += d - tmp;
tmp = 0;
}
}
else if (d == tmp)
{
res += tmp + d;
tmp = 0;
}
}
return res + tmp;
}
int main()
{
const char *romanNumbers[] = {
"IV", "VIII", "IX", "XXXI", "XLVI", "XCIX", "DLXXXIII", "DCCCLXXXVIII",
"MDCLXVIII", "MCMLXXXIX", "MMX", "MMXII", "MMMCMXCIX"
};
for (const char **r = romanNumbers; r != romanNumbers + sizeof(romanNumbers) / sizeof(*romanNumbers); ++r)
cout << *r << " is " << fromRoman(*r) << endl;
}
输出:
IV is 4
VIII is 8
IX is 9
XXXI is 31
XLVI is 46
XCIX is 99
DLXXXIII is 583
DCCCLXXXVIII is 888
MDCLXVIII is 1668
MCMLXXXIX is 1989
MMX is 2010
MMXII is 2012
MMMCMXCIX is 3999