查找字符串中的字符时遇到问题

问题描述:

虽然我有Java的基本知识,但我是新来的C++,我试图制作一个程序来转换罗马数字输入,然后找到相应的阿拉伯数字并输出它。然而,我有一个问题,找到罗马数字中的具体前缀,我试图使用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

对'的std :: cin.eof支票( )'没有多大意义。由于您已经检查过输入是否成功,所以它不会造成太大的伤害,但是如果没有空格后面的空格,例如文件末尾缺失的换行符,它会阻止最后一个值。只要删除它!顺便说一句,'std :: cin >> line'不会读取一行,而是读取一个字。如果你真的想读取一行,请改用'std :: getline(std :: cin,line)'。 –

+0

我建议你看看'std :: map'。您可以使用罗马数字字符串作为键,将小数值用作[键,值]对中的值。 –

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_digits const string,以防止意外修改它们。

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

+0

非常感谢,未来我会考虑这些事情。 ^^ – 4593DDJS

std::string::find()功能不返回布尔值,而是返回找到的子串的std::string::npos的位置,或者,如果没有这样的位置。因此,您的测试应该看起来像这样:

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

当然,尝试四次相同的测试顺序并没有多大意义。您可能想要索引i从千位数组中选择适当的字符串,并只进行一次测试。当然,你会想要颠倒字符串的顺序或者倒计数以便有用。

对于其他检查你可能应该使用find()以及可能会有更多的数字如下。

我觉得这个代码更简单,我没有执行错误检查,但它不应该是很难:

#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