【问题描述】
英文电影中参演人员名单一般以某种方式进行排版显示。给定一个未排版的文件listin.txt,该文件中每行参演人员名单由冒号":"分隔成前后两部分,但格式杂乱无章,单词(由除空格和水平制表符之外的其它字符构成)之间可能有多个空格或水平制表符分隔。编写程序,要求将其按如下排版规则排版输出到另一个文件listout.txt中:
1.从标准输入整数,作为排版后所有各行冒号在一行中的固定位置,输入的整数肯定大于排版后所有各行冒号前的字符个数,位置从1开始计数;
2.冒号左边的单词串以行头为基准左对齐,左边的最后一个单词与冒号之间以空格填充;冒号右边的单词串以冒号基准左对齐,最后一个单词后只有回车换行符,不再有其它字符;
3.冒号左右两边的单词间都只有一个空格分隔,并且要求冒号两边至少各有一个空格。
假设输入文件中每行字符个数不超过100。
【输入形式】
待排版的参演人员名单从当前目录下的listin.txt文件中读入,表示冒号位置的整数从标准输入读入。
【输出形式】
排版后的参演人员名单输出到当前目录下的listout.txt中。
【输入样例】仅为示例
假设文件listin.txt内容为:
Supervising Digital Colorist:Steven J. Scott
Second Colorist :Andrew Francis
Digital Intermediate Producer:Loan Phan
Digital Intermediate Editor: Devon Miller
键盘输入:40
【输出样例】
【样例说明】
输入的文件listin.txt中有四行参演人员名单,要求排版后冒号位于第40个字符的位置,按照上述排版规则输出到文件listout.txt中。以上仅为参考示例,因为浏览器的显示可能带来误差,以题面文字描述为准。
一、思路:
把因为不确定中间的是空格还是制表符,我们就遇上制表符就全都换成空格。然后遍历查找是否有连续空格,有的话删除到只剩下一个。最后计算一下40这个位置到左边部分一共需要多少个空格,在填充中间部分就好了
二、代码实现:
1.开始的必要找两个文件的环节(如果运行结果是文件不存在,表明可能是读取的时候不存在那个listin.txt文件,因为是ofstream和fstream才会在找不到文件的时候给你自动创建一个)
//找两个文件
fstream infile("listin.txt", ios::in); //其实默认就是读取,用ifstream不会自动创建,用ofstream或者fstream才行
if (!infile) {
cerr << "open error!" << endl;
exit(1); //表示立即终止程序的执行(貌似return 也行?)
}
ofstream outfile("listout.txt",ios::out); //创建输出文件流对象,关联文件listout.txt
if (!outfile) { //文件打开失败返回一个值
cerr << "open error!" << endl;
exit(1);
}
2.之后是循环读取一行的字符串,再进行处理,为避免臃肿写成函数形式
string line;
while (getline(infile, line)) {
string formatted_line = rewrite(line, location);
outfile << formatted_line << endl;
}
这是函数部分
//排版文字
string rewrite(const string& line, int location) {
istringstream iss(line);
string left, right;
getline(iss, left, ':'); //获取一串字符,直到遇上":"
getline(iss, right);
//首尾处理,但感觉应该有更好的方法,还是写复杂了(那两个left.find_first_not_of和find_last_not_of也是我上网查的)
left.erase(0, left.find_first_not_of(" \t")); //删除0到“第一个不是空格或者制表符”之间的所有元素
left.erase(left.find_last_not_of(" \t") + 1);
right.erase(0, right.find_first_not_of(" \t"));
right.erase(right.find_last_not_of(" \t") + 1);
//嵌套一个删除空格的函数
rmove(left);
rmove(right);
//计算左边需要填充的空格数
int padding = location - left.length() -1; //-1是要除去:本身所在的位置
//排版
string formatted_line = left ;
formatted_line.append(padding, ' '); //填空空格
right = ": " + right; //因为不会整体处理把这个冒号弄上去,我就分成了left和right两部分
formatted_line += right;
return formatted_line;
}
这是嵌套函数中删除空格的部分
//删除多个连续空格,保留当前位置的一个
void rmove(string& str) {
//把所有制表符都替换为一个空格
for (size_t i = 0; i < str.length(); i++) {
if (str[i] == '\t') {
str.replace(i, 1, " ");
}
}
//删除空格
bool sign = false; //保证初始时候至少有一个空格
auto it = str.begin();
while (it != str.end()) {
if (*it == ' ') {
if (sign) {
it = str.erase(it); //持续检查当前位置
}
else {
sign = true;
it++; //说明当前位置已经无多余的空格
}
}
else {
sign = false;
it++;
}
}
}
三、完整代码
#include<iostream>
#include<fstream>
#include<sstream> //istringstream
#include<vector>
#include<string>
using namespace std;
//删除多个连续空格,保留1
void rmove(string& str) {
//将制表符替换为空格(替换剩下部分版本;)
//auto tab_len = 8;
//for (size_t i = 0, pos = 0; i < str.length(); i++) {
// if (str[i] == '\t') {
// size_t len_to_next = tab_len - (pos % tab_len); //填充空格的长度
// str.replace(i, 1, len_to_next, ' ');
// //更新索引
// i += len_to_next - 1;
// //更新位置计数器
// pos += len_to_next - 1;
// }
//}
//把所有制表符都替换为一个空格版
for (size_t i = 0; i < str.length(); i++) {
if (str[i] == '\t') {
str.replace(i, 1, " ");
}
}
//删除空格
bool sign = false; //保证初始时候至少有一个空格
auto it = str.begin();
while (it != str.end()) {
if (*it == ' ') {
if (sign) {
it = str.erase(it); //持续检查当前位置
}
else {
sign = true;
it++; //说明当前位置已经无多余的空格
}
}
else {
sign = false;
it++;
}
}
}
//排版文字
string rewrite(const string& line, int location) {
istringstream iss(line);
string left, right;
getline(iss, left, ':'); //获取一串字符,直到遇上":"
getline(iss, right);
//去除空格
left.erase(0, left.find_first_not_of(" \t")); //删除0到“第一个不是空格或者制表符”之间的所有元素
left.erase(left.find_last_not_of(" \t") + 1);
right.erase(0, right.find_first_not_of(" \t"));
right.erase(right.find_last_not_of(" \t") + 1);
rmove(left);
rmove(right);
//计算左边需要填充的空格数
int padding = location - left.length() -1; //-1 冒号前面的第一个空格
//构建排版
string formatted_line = left ;
formatted_line.append(padding, ' '); //填空空格
right = ": " + right;
formatted_line += right;
return formatted_line;
}
int main() {
int location = 0;
cin >> location; //表示冒号的位置
//找两个文件
fstream infile("listin.txt", ios::in); //其实默认就是读取,用ifstream不会自动创建,用ofstream或者fstream才行
if (!infile) {
cerr << "open error!" << endl;
exit(1); //表示立即终止程序的执行(貌似return 也行?)
}
ofstream outfile("listout.txt",ios::out); //创建输出文件流对象,关联文件listout.txt
if (!outfile) { //文件打开失败返回一个值
cerr << "open error!" << endl;
exit(1);
}
string line;
while (getline(infile, line)) {
string formatted_line = rewrite(line, location);
outfile << formatted_line << endl;
}
infile.close();
outfile.close();
return 0;
}
之后我的完整代码应该都会像这样。。。把一些奇怪的想法和自言自语加进去。(说白了就是懒得再找注释然后删除了,这人。。。)谨慎辨别,思路看思路为主,不建议直接copy。
标签:right,str,读写,空格,文本文件,line,排版,left From: https://blog.csdn.net/2403_87544412/article/details/144422754