查找字符串中的字符时遇到问题
虽然我有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.我知道这与我的程序找到的顺序有关字符串中的前缀,但是我不确定如何解决它,所以任何帮助都会很棒。
再次感谢
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循环中定义。
非常感谢,未来我会考虑这些事情。 ^^ – 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
对'的std :: cin.eof支票( )'没有多大意义。由于您已经检查过输入是否成功,所以它不会造成太大的伤害,但是如果没有空格后面的空格,例如文件末尾缺失的换行符,它会阻止最后一个值。只要删除它!顺便说一句,'std :: cin >> line'不会读取一行,而是读取一个字。如果你真的想读取一行,请改用'std :: getline(std :: cin,line)'。 –
我建议你看看'std :: map'。您可以使用罗马数字字符串作为键,将小数值用作[键,值]对中的值。 –