顺序我正在检查输出错误的字符串

Order I am checking strings getting wrong output

本文关键字:错误 字符串 输出 检查 顺序      更新时间:2023-10-16

我是c++的新手,虽然我有Java的基本知识,但我正在尝试制作一个程序,转换罗马数字输入,然后找到等效的阿拉伯数字并输出。然而,我遇到了一个问题,即如何在罗马数字中找到特定前缀的正确顺序,例如,因为它要单独检查"X"并删除它;我的程序将输入"IX"翻译为11,而实际上它是9。我知道这与我的程序在字符串中查找前缀的顺序有关,但我不确定如何修复它,所以在这方面提供任何帮助都会很好。

当前代码:

    #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;
}

如有任何帮助,我们将不胜感激。

使用贪婪解析策略。也就是说,只要你有一个有效的数字,就可以消耗尽可能多的输入。例如,使用您的示例输入:

MCCCXXXVII

首先看M,它是一个有效的数字。然后看MC,这不是一个有效的数字,所以你消耗M,然后从C开始。

C是有效数字吗?对CC是有效数字吗?对CCC是有效数字吗?对CCCX是有效数字吗?否,因此消耗CCC,然后从X重新开始。

看到照片了吗?

我没有多想,但在我看来,这个问题比你试图解决的问题更简单……我相信你应该能够一次一个字符地解析字符串,更新值。

一般的想法是,从结果设置为0开始,一次读取一个字符,同时记住前一个字符(最初设置为无法出现在输入中的字符。对于读取的每个字符,将该值乘以该字符的值(M=1000,D=500,C=100,…)

当读取的最后一个字符的面额低于此字符时,就会出现奇怪的情况。在这种情况下,您只需要修复该值。

例如,在MCD中,你会开始递增1000,然后递增100,然后找到500,但这比C大,所以你需要修正:递减之前添加的100,加400,总共1400。

您应该使用调试器!以下是我的发现:

  • IX 中的用户类型

  • 一切都很好,直到你进入贯穿你的tens阵列的for循环:

  • tens数组中循环时,会检查
    else if (line.find("X") != string::npos)

  • 返回true。应该这样吗?9不应在tens中。

  • 一个问题的解决方案是检查它是否不是9:

    else if (line.find("X") != string::npos && line != "IX")

编辑:

这只是一个快速的破解,从长远来看,你应该听从David Rodríguez的建议,简化你的解决方案。