天梯赛L3-019 代码排版 (28分)c++

某编程大赛中设计有一个挑战环节,选手可以查看其他选手的代码,发现错误后,提交一组测试数据将对手挑落马下。为了减小被挑战的几率,有些选手会故意将代码写得很难看懂,比如把所有回车去掉,提交所有内容都在一行的程序,令挑战者望而生畏。

为了对付这种选手,现请你编写一个代码排版程序,将写成一行的程序重新排版。当然要写一个完美的排版程序可太难了,这里只简单地要求处理C语言里的for、while、if-else这三种特殊结构,而将其他所有句子都当成顺序执行的语句处理。输出的要求如下:

默认程序起始没有缩进;每一级缩进是 2 个空格;
每行开头除了规定的缩进空格外,不输出多余的空格;
顺序执行的程序体是以分号“;”结尾的,遇到分号就换行;
在一对大括号“{”和“}”中的程序体输出时,两端的大括号单独占一行,内部程序体每行加一级缩进,即:

{
  程序体
}

for的格式为:

for (条件) {
  程序体
}

while的格式为:

while (条件) {
  程序体
}

if-else的格式为:

if (条件) {
  程序体
}
else {
  程序体
}

输入格式:
输入在一行中给出不超过 331 个字符的非空字符串,以回车结束。题目保证输入的是一个语法正确、可以正常编译运行的 main 函数模块。

输出格式:
按题面要求的格式,输出排版后的程序。

输入样例:

int main()  {int n, i;  scanf("%d", &n);if( n>0)n++;else if (n<0) n--; else while(n<10)n++; for(i=0;  i<n; i++ ){ printf("n=%d\n", n);}return  0; }

输出样例:

int main()
{
  int n, i;
  scanf("%d", &n);
  if ( n>0) {
    n++;
  }
  else {
    if (n<0) {
      n--;
    }
    else {
      while (n<10) {
        n++;
      }
    }
  }
  for (i=0;  i<n; i++ ) {
    printf("n=%d\n", n);
  }
  return  0;
}

我用了递归来做这个题,代码中的主力是 eval 函数与 evalKeyword 函数,eval函数中传入一个参数 idx ,表示它负责的代码部分的下标的开始位置,当 idx 处为左花括号时,他会一直往后处理直到遇到与开始处相匹配的右花括号。当处理的过程中遇到关键字时,就交给 evalKeyword 处理,evalKeyword 中遇到关键字后面需要处理的代码段时再调用 eval,这样两个函数互相递归调用。
evalKeyword 函数:

  • 如果是 else 就直接根据后面有没有花括号两种情况交给 eval 处理
  • 如果是其他关键字,就先处理后面的括号,再看有没有花括号并 eval
  • 最后如果处理的关键字是 if 的话,处理完 if 就接着判断后面有没有 else,如果有的话就递归调用自己处理 else
    注意以下几种情况
  • 括号中可能还会有括号 if((a-b)*c>0)
  • 注意处理引号 printf(";;;;"); or printf("if(a>b)");
  • 引号包括单引号 char ch=';'; or char ch='\'';(数据中似乎没有这种情况)

测试点1 格式错误 不知道哪里出了问题T_T

#include <bits/stdc++.h>
using namespace std;
string keyword[]={"if","else","for","while"};
string code;
void eval(int &idx,string space,bool left);
void evalKeyword(int &idx,int type,string space);
bool Space(char ch)
{
    if(ch>='a'&&ch<='z') return false;
    if(ch>='A'&&ch<='Z') return false;
    if(ch>='0'&&ch<='9') return false;
    if(ch=='_') return false;
    return true;
}
// 检查 str 是否是关键字,idx为关键字字符串后面的第一个字符的下标
int check(string str,int idx)
{
    int type;
    for(type=0;type<4;type++) {
        if(str==keyword[type]) break;
    }
    return Space(code[idx])?type:4;
}
// 括号、引号中的内容一定在同一行
void evalsp1(int &idx) // 处理括号
{
    cout<<code[idx++];
    while(code[idx]!=')') {
        if(code[idx]=='(') {
            evalsp1(idx);
        } else {
            cout<<code[idx++];
        }
    }
    cout<<code[idx++];
}
string evalsp2(int &idx) // 处理引号
{
    string res="";
    res+=code[idx++];
    while(code[idx]!='"') {
        if(code[idx]=='\\') res+=code[idx++];
        res+=code[idx++];
    }
    res+=code[idx++];
    return res;
}
string evalsp3(int &idx) // 处理单引号
{
    string res="";
    res+=code[idx++];
    while(code[idx]!='\'') {
        if(code[idx]=='\\') res+=code[idx++];
        res+=code[idx++];
    }
    res+=code[idx++];
    return res;
}
void eraseSpace(int &idx) // 删除空格
{
    while(code[idx]==' ') idx++;
}
// 处理关键字,idx为关键字字符串后的第一个字符的下标,type为关键字类型(看代码开头的keyword数组,space为当前的花括号的缩进空格)
void evalKeyword(int &idx,int type,string space)
{
    cout<<space<<keyword[type]<<' ';
    string now=space+"  ";
    eraseSpace(idx); // 删除多余空格
    if(type==1) { // else的情况后面没有括号
        if(code[idx]=='{') { // 后面带了花括号
            eval(idx,space,false);
        } else {
            cout<<'{'<<'\n';
            eval(idx,space,false);
            cout<<space<<'}'<<'\n';
        }
    } else { // 其他情况后面会有括号
        evalsp1(idx);
        // 处理完括号之后记得加一个空格
        cout<<' ';
        eraseSpace(idx);
        if(code[idx]=='{') {
            eval(idx,space,false);
        } else {
            cout<<'{'<<'\n';
            eval(idx,space,false);
            cout<<space<<'}'<<'\n';
        }
        eraseSpace(idx);
        if(type==0&&check(code.substr(idx,4),idx+4)==1) {
            idx+=4;
            evalKeyword(idx,1,space);
        }
    }
}
// 处理代码段,idx为代码段开头的第一个字符下标,space为缩进空格,left代表花括号(如果有的话)前面是否添加缩进
void eval(int &idx,string space,bool left)
{
    string temp="",now=space+"  ";
    bool flag=code[idx]!='{'; // 是否处理单句
    if(flag) {
        bool have_keyword=false;
        eraseSpace(idx); // 删去句首空格
        while(code[idx]!=';') {
            temp+=code[idx++];
            int res=check(temp,idx);
            if(res<4) { // 出现了关键字
                have_keyword=true;
                evalKeyword(idx,res,now);
                //只有一句并且包含关键字,则不需要再找分号,直接结束
                return;
            }
        }
        if(!have_keyword) { // 输出普通语句
            temp+=code[idx++];
            cout<<now<<temp<<'\n';
        }
    } else {
        if(left) cout<<space;
        cout<<code[idx++]<<'\n';//将前花括号打出
        while(code[idx]!='}') { // 开始找右花括号
            eraseSpace(idx); // 删除多余空格
            while(code[idx]!=';'&&code[idx]!='{'&&code[idx]!='}') {
                if(code[idx]=='"') {
                    temp+=evalsp2(idx);
                    continue;
                } else if(code[idx]=='\'') {
                    temp+=evalsp3(idx);
                    continue;
                }
                temp+=code[idx++];
                int res=check(temp,idx);
                if(res<4) {
                    evalKeyword(idx,res,now);
                    temp="";
                    break;
                }
            }
            if(code[idx]==';') { // 如果只是普通语句
                temp+=code[idx++];
                cout<<now<<temp<<'\n';
                temp="";
            } else if(code[idx]=='{') { // 发现了代码块中的代码块
                eval(idx,now,true);
            }
        }
        cout<<space<<code[idx++]<<'\n';//打出右花括号
    }
}
int main()
{
    // ios::sync_with_stdio(false),cin.tie(0);
    getline(cin,code);
    int idx=0;
    while(code[idx]!='{') idx++; // 找到第一个花括号的位置
    cout<<"int main()\n";
    eval(idx,"",true);
    return 0;
}

====================================================
二编,终于过了
测试点1 int main() 中间的括号中可能有空格,需要特殊处理
修改部分如下

int main()
{
    // ios::sync_with_stdio(false),cin.tie(0);
    getline(cin,code);
    int idx=0;
    while(code[idx]!='{') idx++;
    // 不能直接输出
    // cout<<"int main()\n";
    for(int i=0;i<idx;i++) {
        cout<<code[i];
        if(code[i]==')') break;
    }
    cout<<'\n';
    eval(idx,"",true);
    return 0;
}
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值