题目概述:
1.给定字典dict.txt,第一行为提示有多少行,其余第一列为需要被替换的字符,第二列为需要替换 上的字符;
2.给定一个输入文件input.txt,其中包含多种运算:[m,n]求m,n的最小公倍数Lcm,{m,n}求m,n的最大公约数Gcd。
对()内有三种形式:(y/m/d)求y年m月d日为星期几,(m,n)求组合数Cm n,(a)求a的阶乘。
求工资数,其中a为工作小时,b为每小时工资((如果时间小于0或大于一周的总时间直接输出0)。若每周工作小时超过60小时,则超过60小时的部分按原工资3倍的加班工资来计算,每周工作小时超过40小时而不超过60小时的工资按原工资的1.5倍的加班工资来计算。)
单独一个数字则不做任何计算。
3.具体步骤:
(1)从特定文本文件中读取一个特定格式字典,包括①从数字到数值的对应,②从字母到数值的对应,③括号和计算符号不作转换;
(2)再从一个文本文件中读取原始符号串,并实现将原始符号串根据字典进行必要的转换。注意,转换后的符号串需要用链表存储;
(3)针对转换后的符号串,按下列要求完成相应的计算,并用两侧各附有一个空格的计算结果替换原来的符号串;
(4)若是数字转换,3换55需要换,但33不是3,不能替换成5555;无需重复替换如3换5,5换7;
(5)再针对处理后的、由空格分隔的数据进行排序;
(6)最后将排好序的数据,以格式化的形式存入文件;
当时觉得挺折磨的,文件读取与输出,链表操作都是小白,得使劲瞪眼bing,google...一开始字典是一一对应的,我便想存进同一个数组中,偶数(0开始)为第一列被替换字符,奇数为替换上去地的字符。后面需要一对多,也就是3可能换成55,g可能换成777等等。工资数那里由于我是一个一个读取字符来判断符号、计算符号数字的,于是出现了小数计算与多个小数点判断的问题,但所幸原理与算多位数相同。尽管仍有一些不足,但起码现在能看...
完整代码:
#include#include #include #include #include using namespace std; //全局变量 string dicbook[99]{}; //总字典 // 将第一列与第二列合并而成的长字符串数组 string dicbook1[99]{}; //字典第一列即要被转换的字符 string dicbook2[99]{}; //字典第二列即被转换成的字符 char c; //ReadDic字符串中间变量 int row = 0; //行数 string needchange[99]{}; //转换成需要修改的字符串数组 int dicbooklenth = 0, dicbook1lenth = 0, dicbook2lenth = 0, needchangelenth = 0; //各字符串数组长度存储 string dicttxt, inputtxt; //字典,输入 string temptxt, answerdata; //临时,答案 //事先声明的函数 void ReadDic(); void Getinput(); //数学 int Gcd(int m, int n) //求m,n的最大公约数 { if (n == 0) { return m; } return Gcd(n, m % n); } int Lcm(int m, int n) //求m,n最小公倍数 { return m * n / Gcd(m, n); } int Fac(int n) //求n的阶乘 { for (int i = n - 1; i >= 1; i--) { n *= i; } return n; } int CombinatorialNumber(int n, int m) //求m,n的组合数,无论m和n谁大谁小 { int sum = 1; int tem = 1; if (m > n) { tem = n; n = m; m = tem; } for (int i = 1; i <= m; i++) { sum = sum * (n - m + i) / i; } return sum; } //工资 double Salary(double time, double per) //求工资 { double total = 0; if (time <= 0 || time >= 168) total = 0; else if (time > 0 && time <= 40) total = time * per; else if (time > 40 && time <= 60) total = 1.5 * (time - 40) * per + 40 * per; else if (time > 60 && time < 168) total = 3 * (time - 60) * per + 1.5 * 20 * per + 40 * per; return total; } //年份 int LeapYear(int year) //判断闰年 { if (year % 400 == 0 || year % 100 != 0 && year % 4 == 0) return 1; else return 0; } int WhatDay(int year, int month, int day) // 判断某年月日是星期几 { int i = 0, result = 0; if (year > 0 && month <= 12 && month > 0 && day <= 31 && day > 0) { if (LeapYear(year) && month == 2 && day > 29) { return result; } else if (LeapYear(year) == 0 && month == 2 && day > 28) { return result; } else if (month == 4 || month == 6 || month == 9 || month == 11) { if (day > 30) return result; } for (i = 1; i < year; i++) { result += (LeapYear(i) + 365) % 7; } for (i = 1; i < month; i++) { if (i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12) { result += 31 % 7; result %= 7; } else if (i == 4 || i == 6 || i == 9 || i == 11) { result += 30 % 7; result %= 7; } else if (i == 2) { result += (28 + LeapYear(year)) % 7; result % 7; } } result += day % 7; result %= 7; if (result == 0) result = 7; return result; } else return result; } //字典转换 string Change(string str) //对字典给定的特定字符进行转换 { int j = 1, n = 1, count = 0; for (int i = 0; i < dicbooklenth; i += 2) { n = dicbook[j].length(); j += 2; count++; if (0 < n && n < 2) { replace(str.begin(), str.end(), dicbook[i][0], dicbook[i + 1][0]); } else if (n >= 2) { if (str == dicbook[i]) str = dicbook[i + 1]; else continue; } } return str; } //文件操作 void ReadDic() //读取字典并把字典内容存到全局字符数组dicbook { int count = 0; //判断为第一列还是第二列 int pd = 0; //控制判断是否为多位数 int mulnumpolen = 0; ifstream dic(dicttxt); while (!dic.eof()) { c = dic.get(); if (c == '#') { c = dic.get(); c = dic.get(); row = c - '0'; c = dic.get(); c = dic.get(); } if (c == ' ') { cout << "空格"; count++; pd = 0; continue; } else if (c == 'n') { cout << "换行" << endl; count--; pd = 0; continue; } else if (c == EOF) { cout << "换行" << endl; count--; pd = 0; continue; } if (count == 0) { dicbook1[dicbook1lenth] = c; dicbook1lenth++; } else if (count == 1) { pd++; if (pd < 2) { dicbook2[dicbook2lenth] = c; ++dicbook2lenth; } else if (pd >= 2) { dicbook2[dicbook2lenth - 1] += c; } } cout << c; } cout << "行数:" << row; cout << endl; cout << "第一列的元素:"; for (int i = 0; i < dicbook1lenth; i++) { cout << dicbook1[i] << " "; } cout << endl; int mpl = 0; cout << "第二列的元素:"; for (int i = 0; i < dicbook2lenth; i++) { cout << dicbook2[i] << " "; } cout << endl; int countb1 = 0, countb2 = 0; dicbooklenth = dicbook1lenth + dicbook2lenth; for (int i = 0; i < dicbooklenth; i++) { if (i % 2 == 0) { dicbook[i] = dicbook1[countb1]; countb1++; } else { dicbook[i] = dicbook2[countb2]; countb2++; } } cout << endl; cout << "总字典:"; for (int i = 0; i < dicbooklenth; i++) { cout << dicbook[i] << " "; } dic.close(); //关闭文件 } void Getinput() //得到输入的文件将其转换为字符串形式 { ifstream inpu(inputtxt); while (!inpu.eof()) { inpu >> needchange[needchangelenth++]; //逐个放入needchange 字符串里 } inpu.close(); //关闭文件 } void FuncRealize() //字典转换与输入的具体实现 { ifstream ifs; char ch = 0; string str; list
List1; int i = 0; ifs.open(inputtxt, ios::in);//读取文件 while (ifs.get(ch)) //得到一个string类型的input作为转换的另一个str { if (ch == '<') { str += ch; while (ch != '>') { ifs.get(ch); if (ch == ' ') continue; str += ch; } } else str += ch; i++; } ifs.close(); cout << "转换前的字符串:" << endl; cout << str << endl; int len = str.length(); string newstr; //获得新的string(删除了<>里的空格) ReadDic(); //读字典 Getinput(); //得到输入 for (int i = 0; i < len; i++) //逐个替换字符 { if ('9' >= str[i] && str[i] >= '0') //如果读到了数字 { if (i == 0 && (str[i + 1] > '9' || str[i + 1] < '0')) //如果数字在第一位且下一位是符号,转换 { string temstr; temstr = str[i]; newstr += Change(temstr); } //小数考虑 if ( (i > 0 && i < len - 1 && str[i + 1] > '9') && (str[i + 1] < '0' && str[i - 1] == '.') ) //如果数字不在第一位且不在最后一位,且后一位为符号前一位为小数点,不改 { newstr += str[i]; } else if ((i > 0 && i < len - 1 && str[i + 1] > '9') && (str[i - 1] < '0' && str[i + 1] == '.') ) //如果数字不在第一位且不在最后一位,且前一位为符号后一位为小数点,也不改 { newstr += str[i]; } else if ( (i > 0 && i < len - 1) && (str[i + 1] > '9' || str[i + 1] < '0') && (str[i - 1] > '9' || str[i - 1] < '0') ) //如果数字不在第一位且不在最后一位,前后都是符号 { if ( (str[i + 1] < '0' && str[i - 1] == '.') || (str[i - 1] < '0' && str[i + 1] == '.') ) //前后若有小数点,不改 { newstr += str[i]; } else //其他的,对照字典修改 { string temstr; temstr = str[i]; newstr += Change(temstr); } } else if (i == len - 1 && (str[i - 1] > '9' || str[i - 1] < '0')) 如果数字在最后一位,且前一位是符号,按照字典修改 { string temstr; temstr = str[i]; newstr += Change(temstr); } else newstr += str[i]; //其他不改 } else //读到符号,改 { string temstr; temstr = str[i]; newstr += Change(temstr); } } cout << endl; cout << endl << "转换后的字符串:" << endl; cout << newstr; ofstream newinpu;//写入新文件 newinpu.open(temptxt, ios::out); newinpu << newstr << endl; newinpu.close(); ifstream newread;//读新文件 newread.open(temptxt, ios::in); char temch; //临时字符,一个个取新文件里的字符串的内容 while (newread.get(temch)) //当没有读到EOF时 { if ('9' >= temch && temch >= '0') //如果读到数字,下有同理 { int a = 0, b = 0, c = 0; //三个中间变量,将读到的数字转化为int型带入函数计算 while (temch != ' ') //读取数字 { if ('9' >= temch && temch >= '0') //读了几位就要得到几位 { a = temch - '0'; //假设有字符串‘24’,先读2,得到int型2,b*10 = 0,b+=a = 2,判断还为数字,再读进4,得到int型a = 4,此时b*=10 = 20, b+=a = 24 b *= 10; b += a; } else { newread.get(temch); continue; //读到符号,保存,接着读 } newread.get(temch);// 接着读 } List1.push_back(b); //放进List1链表里 } else if (temch == '{')//当读到“{”,求最大公约数 { int a = 0, b = 0, c = 0; while (temch != '}') { if ('9' >= temch && temch >= '0') { a = temch - '0'; b *= 10; b += a; } else { c = b; b = 0; newread.get(temch); continue; //c是第一个数据 } newread.get(temch); } List1.push_back(Gcd(c, b)); } else if (temch == '<')//当读到“<”,求工资 { double a = 0, b = 0, c = 0, point = 0, tempoint = 0; while (temch != '>') { if ('9' >= temch && temch >= '0') { a = temch - '0'; b *= 10; b += a; newread.get(temch); if (temch == '.') //如果为小数 { double plus = 0.1; newread.get(temch); while ('0' <= temch && temch <= '9') //当读的都是数字时,算小数部分为多少,方法与*=10得多位数类似 { tempoint = temch - '0'; tempoint = tempoint * plus; point += tempoint; plus *= 0.1; //每多一位往后退一位 newread.get(temch); // cout << "point" << point; 测试point对不对 } b = b + point; } } else { c = b; b = 0; point = 0; //读到符号时初始化b与小数部分,这样就可以得到两个小数放进Salary中的效果 newread.get(temch); continue; //c是第一个数据 } } // cout << "cb" << c << " " << b; //检查cb是否有输入,输入是否正确 List1.push_back(Salary(c, b)); } else if (temch == '[') //当读到“[”,求最小公倍数 { int a = 0, b = 0, c = 0; while (temch != ']') { if ('9' >= temch && temch >= '0') { a = temch - '0'; b *= 10; b += a; } else { c = b; b = 0; newread.get(temch); continue; //c是第一个数据 } newread.get(temch); } List1.push_back(Lcm(c, b)); } else if (temch == '(') //当读到“(”,进行下一步判断 { int n = 0, m = 0, s = 0, times = 0; //n,m,s是判断括号里有什么,程序该进哪个循环的重要判据 int a = 0, b = 0, c = 0, d = 0, f = 0; //中间变量 while (temch != ' ') { times++; //记录读了多少次——读了多少字节 newread.get(temch); if (temch == ',') n++; else if (temch == '(') m++; else if (temch == '/') s++; } // cout << "nms" << n << m << s; 检查,查看()里的是什么符号的判据是否成功 newread.seekg(-times, ios::cur); //移动文件读指针回原先位置'(' newread.get(temch); //读取e为值 if (m != 0) { while (temch != ' ') { newread.get(temch); continue; } } else if (n == 0 && m == 0 && s == 0)//求阶乘 { while (temch != ')') { if ('9' >= temch && temch >= '0') { a = temch - '0'; b *= 10; b += a; } else { c = b; b = 0; newread.get(temch); continue; } newread.get(temch); } List1.push_back(Fac(b)); } else if (n == 1 && m == 0 && s == 0)//求组合数 { while (temch != ')') { if ('9' >= temch && temch >= '0') { a = temch - '0'; b *= 10; b += a; } else { c = b; b = 0; newread.get(temch); continue; } newread.get(temch); } List1.push_back(CombinatorialNumber(c, b)); } else if (n == 0 && m == 0 && s == 2)//求星期几 { int num = 0; while (temch != ')') { if ('9' >= temch && temch >= '0') { a = temch - '0'; b *= 10; b += a; } else { num++; if (num == 1) { c = b; b = 0; newread.get(temch); continue; //第一个数 } else { d = b; b = 0; newread.get(temch); continue; //第二个数,b是第三个 } } newread.get(temch); } List1.push_back(WhatDay(c, d, b)); } } } newread.close(); ofstream ouput; //放入文件中 ouput.open(answerdata, ios::out); list ::iterator List2; List2 = List1.begin(); if (ouput) { while (List2 != List1.end()) { ouput << *List2 << " ";//写入文件 List2++; } if (List2 == List1.end()) { ouput << endl; } } else { cout << "No file found" << endl; } ouput.close(); //由于下面又输入了一遍排序后的,这里的输入文件只是临时的,文件中并没有,这里仅为了answer能够输出未排序的回显 ifstream answer(answerdata); //读文件,输出回显 string line; int count = 0; if (answer) // 有该文件 { cout << endl << endl << "Result(排序前):" << endl; while (getline(answer, line)) // line中不包括每行的换行符 { cout << line << endl; } } else // 没有该文件 { cout << "No file found" << endl; } cout << endl; answer.close(); List1.sort(); cout << "排序后:" << endl; list ::iterator List3; List3 = List1.begin(); while (List3 != List1.end()) { cout << *List3 << " "; // 输出回显 List3++; } ouput.open(answerdata, ios::out); List3 = List1.begin(); if (ouput) { while (List3 != List1.end()) { ouput << *List3 << " ";//写入文件 List3++; } } else // 没有该文件 { cout << "No file found" << endl; } ouput.close(); } int main() { cout << "请输入 字典 的完整地址:"; cin >> dicttxt; cout << "请输入 输入 的完整地址:"; cin >> inputtxt; cout << "请输入 临时存储 的完整地址:"; cin >> temptxt; cout << "请输入 存放排序后的字符串 的完整地址:"; cin >> answerdata; FuncRealize(); system("pause"); }
文本准备:
dict.txt:
# 7(其实这个可有可无)
1 2
a 19
b 10
4 8
c 9
k 20
6 5
input.txt: 3 (5,b) a 11 {44,11} 19 (6) <9.5,12.45> 99 (k/2/23) 77 1000 [b,1]
temp.txt与answerdata.txt均为空。
输出示例:
(完整地址可以直接把txt拖进,之前还真不知道...(汗))
具体某些问题注释也写了一些理解,具体操作仔细读读还是能够明白文件txt的读取输出也其实挺好懂的,其使输入与输出更加灵活。但是链表这个东西确实不错!值得深入学习与探究,与数组有类似,但功能上感觉更加强大...当然,关系网也更加复杂了。链表详细很多大佬写的那是又细又好,想参悟链表,咱还得继续学,先继续参考大佬的吧!
参考链表知识链接:【C++】链表及基本操作_撸代码的Ellie的博客-CSDN博客_c++链表
c++链表 - 知乎
初学,粗浅理解,欢迎指正!一起努力!



