1

我是 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。我知道这与我的程序在字符串中找到前缀的顺序有关,但是我不确定如何解决它,所以任何帮助都会很棒。

再次感谢

4

3 回答 3

1

string::find不返回布尔值(如您在下一行看到的)。如果未找到该字符串,则返回一个特殊常量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_digitsconst string以防止意外修改它们。

尝试声明变量尽可能接近它们的第一次使用。char c例如,只需要在您的 while 循环中定义。

于 2013-08-30T00:04:34.643 回答
1

std::string::find()函数不返回布尔值,而是返回找到的子字符串的位置,或者std::string::npos如果没有这样的位置。因此,您的测试可能应该如下所示:

if (line.find("MMM") != std::string::npos) { ... }

当然,尝试四次相同的测试序列并没有多大意义。您可能打算使用索引i从数千个数组中选择适当的字符串并且只进行一次测试。当然,您可能希望颠倒字符串的顺序或倒计时才有用。

对于您可能应该使用的其他检查find()以及后面可能有其他数字。

于 2013-08-29T23:58:04.280 回答
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
于 2013-08-30T04:18:57.220 回答