一种ACM评判内核简易实现 使用C# WEB调用C++编译器的方法

作者:chenjieb520(两片森林)

 

       相信很多做过ACM竞赛题目的人都知道:你提交了代码之后,系统就会对的代码进行编译,然后给出代码的编译的信息还有执行结果。很多人都不太明白如何使用C#进行开发类似的功能。笔者在大学的时期,写过如下一个类,这个类可以解决这个问题。现在自己开了CSDN博客,就将这些自己认为好东西分享给大家,希望对那些需要这些资源的同学有所帮助。

///////////Core.cs   简易的ACM评判黑盒的core类。这个类比较简单,但是大部分的ACM评判思想已经包含进去了。

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Diagnostics;
using System.IO;


/// <summary>
/// Core 的摘要说明
/// </summary>
/// 这是ACM竞赛网评判系统的内核,编写时间2009-03-24
/// 编写:chenjieb520
public class Core
{
    private String CodeStr=null;//所提交的代码
    private String ProgramName = null;//文件名
    private String BasePathName = null;//放所有用户的代码的路径
    private String PathName = null;//用户名所建的文件夹名
    private String PathNameCode = null;//绝对路径下的用户代码
    private String PathNameExe = null;//编译生成的可执行文件
    private String PathNameObj = null;//编译生成的obj文件
    private String StandardInPutStr = null;//从数据中读出的input的内容
    private String InputTxt = null;//将StandardInPut内容写到文件的文件名
    private String OutputTxt = null;
    private String StandardOutPutStr = null;//从数据库中读出的output内容
    private String CodeExe = null;//生成的exe的名字
    private int flage;//编译的类型
    private String javaclassName=null;//用户提交的代码java的文件名
public Core(String LoginName,String TitleID,String CodeStr,String StandardInPut,String StandardOutPut,int flage)
{
        this.CodeStr = CodeStr;
        this.flage =flage;
        if (flage==1)//C语言
        {
            this.ProgramName = TitleID + ".cpp";
        }else if (flage==2)//C++
        {
            this.ProgramName = TitleID + ".cpp";
        }
        else if (flage == 3)//java
        {
           javaclassName = GetJavaCodeClass(CodeStr);
            if (javaclassName=="0")
            {
                this.ProgramName = null;
            }
           this.ProgramName = javaclassName + ".java";
        }else if (flage==4)//c#
        {
            this.ProgramName = TitleID + ".cs";
        }
        this.BasePathName = "J://JmuACM//DugProgram//";
        this.PathName = BasePathName + LoginName;
        this.PathNameCode = BasePathName + LoginName + "//" + ProgramName;
        if (flage==3)//java部分的
        {
            this.CodeExe = javaclassName + ".class";
        }else
        {
            this.CodeExe = TitleID + ".exe";
        }
        this.PathNameObj = BasePathName + LoginName + "//" + TitleID + ".obj";
        this.PathNameExe = BasePathName + LoginName + "//" + this.CodeExe;
        this.InputTxt = BasePathName + LoginName + "//" +  "input.in";
        this.OutputTxt = BasePathName + LoginName + "//" + "output.out";
        this.StandardInPutStr = StandardInPut;
        this.StandardOutPutStr = StandardOutPut;
        if (Directory.Exists(PathName) == false)//如果不存在就创建file文件夹
        {
            Directory.CreateDirectory(PathName);
        }
        StreamWriter sw;
        if (File.Exists(InputTxt))//判断input文件是否存在,为.in的后缀的
        {
            sw = File.AppendText(InputTxt);
        }else
        {
            sw = File.CreateText(InputTxt);
        }
        sw.WriteLine(StandardInPutStr);
        sw.Close();
}
    /* 判断是否可以编译通过
     * 返回-1说明有非法的打印字符
     * 返回1编译通过  返回0编译失败
     * 返回-2出现异常
     * 返回-3,所提交的代码类型不是java,却选择了JAVA类型进行提交
     */
   public  int IsDug()
    {
        string cmd=null;
       if (ProgramName==null)
       {
           return -3;
       }
        if (File.Exists(PathNameExe))
        {
            File.Delete(PathNameExe);//存在上一次的编译的生成的,就进行删除
            if(flage==1||flage==2)
            {
                File.Delete(PathNameObj);
            }
        }
        StreamWriter sw = new StreamWriter(this.PathNameCode);//创建该文件
        sw.Write(CodeStr);
        sw.Close();
        try
        {
            Process myProcess = new Process();
            myProcess.StartInfo.FileName = "cmd.exe";//DOS控制平台
            myProcess.StartInfo.UseShellExecute = false;
            myProcess.StartInfo.CreateNoWindow = true;
            myProcess.StartInfo.RedirectStandardInput = true;
            myProcess.StartInfo.RedirectStandardOutput = true;
            myProcess.StartInfo.RedirectStandardError = true;
            myProcess.StartInfo.WorkingDirectory = this.PathName;
            myProcess.Start();
            StreamWriter sIn = myProcess.StandardInput;//标准输入流
            sIn.AutoFlush = true;
            StreamReader sOut = myProcess.StandardOutput;//标准输入流
            StreamReader sErr = myProcess.StandardError;//标准错误流
            if (flage==1)
            {
                cmd = "cl   "+this.PathNameCode;
            }else if(flage==2)
            {
                cmd = "cl  " + this.PathNameCode;
            }else if (flage==3)
            {
                cmd = "javac   " + this.PathNameCode;
            }else if (flage==4)
            {
                cmd = "csc  " + this.PathNameCode;
            }
            sIn.Write(cmd + System.Environment.NewLine);
            sIn.Write("exit" + System.Environment.NewLine);
            string s = sOut.ReadToEnd();//读取执行DOS命令后输出信息
            string er = sErr.ReadToEnd();//读取执行DOS命令后错误信息
            if (myProcess.HasExited == false)
            {
                myProcess.Kill();
            }
            sIn.Close();
            sOut.Close();
            sErr.Close();
            myProcess.Close();
            if (File.Exists(PathNameExe))
            {
                return 1;
            }
            return 0;
        }
        catch
        {
            return -2;
        }
    }
    //判断是否对了
    //返回1表示该用户已经答对了该题了
    public int ExecProgram()
    {
        int tmpflage=IsDug();
        if (tmpflage==1)
        {
            if (File.Exists(OutputTxt))
            {
                File.Delete(OutputTxt);
            }
            try
            {
                String cmd=null;
                Process myProcess = new Process();
                myProcess.StartInfo.FileName = "cmd.exe";//DOS控制平台
                myProcess.StartInfo.UseShellExecute = false;
                myProcess.StartInfo.CreateNoWindow = true;
                myProcess.StartInfo.RedirectStandardInput = true;
                myProcess.StartInfo.RedirectStandardOutput = true;
                myProcess.StartInfo.RedirectStandardError = true;
                myProcess.StartInfo.WorkingDirectory = this.PathName;
                myProcess.Start();
                StreamWriter sIn = myProcess.StandardInput;//标准输入流
                sIn.AutoFlush = true;
                StreamReader sOut = myProcess.StandardOutput;//标准输入流
                StreamReader sErr = myProcess.StandardError;//标准错误流
                if (flage == 1)
                {
                    cmd = PathNameExe+"<input.in "+">>output.out";
                }
                else if (flage == 2)
                {
                    cmd = PathNameExe + "<input.in " + ">>output.out";
                }
                else if (flage == 3)//java
                {
                    cmd = "java   " + this.PathNameCode + "<input.in " + ">>output.out";
                }else if (flage==4)
                {
                    cmd = PathNameExe + "<input.in " + ">>output.out";
                }
                sIn.Write(cmd + System.Environment.NewLine);
                sIn.Write("exit" + System.Environment.NewLine);
                string s = sOut.ReadToEnd();//读取执行DOS命令后输出信息
                string er = sErr.ReadToEnd();//读取执行DOS命令后错误信息
             //   HttpContext.Current.Response.Write(s + er);
                if (myProcess.HasExited == false)
                {
                    myProcess.Kill();
                }
                sIn.Close();
                sOut.Close();
                sErr.Close();
                myProcess.Close();
                //开始读取执行所生成的文件并且和标准的OutPut.out进行匹配
             //   HttpContext.Current.Response.Write(OutputTxt);
              if (File.Exists(OutputTxt))//这次编译生成的.out文件
               {
                   String tmpstr = File.ReadAllText(OutputTxt);
                   if (tmpstr.Trim().Equals(StandardOutPutStr.Trim()))
                   {
                       DeleteAllFile();//答对的话,就对所有的中间产生的信息进行全部删除
            //           HttpContext.Current.Response.Write("你答对了该题了");
                       return 1;//该用户答对了该题了
                   }else
                   {
                       DeleteAllFile();
                       return 2;//表示虽然编译通过了,但是和.out不匹配
                   }
               }
          //     HttpContext.Current.Response.Write("编译已经成功,但是你所生成的.out文件没有和系统匹配,请将自己的代码的中的Output文件改为:  题目号.out  ");
               DeleteAllFile();
               return 0;//执行程序后,没有生成指定的文件
            }
            catch
            {
            //    HttpContext.Current.Response.Write("代码执行过程中出现了异常,请重新提交,或者稍后提交,报告Bug:[email protected]");
                DeleteAllFile();
                return -1;//执行的过程中抛出了异常
            }
        }else if (tmpflage==-2)
        {
            DeleteAllFile();
            return -2;//编译过程,系统发生了异常
        }
        else if (tmpflage == 0)
        {
       //     HttpContext.Current.Response.Write("编译没有通过,你所提交的代码含有错误");
            DeleteAllFile();
            return -4;//编译没有通过,代码有错误
        }else if (tmpflage==-3)
        {
       //     HttpContext.Current.Response.Write("你所提交的代码不是java类型,却选择了JAVA类型进行编译");
            DeleteAllFile();
            return -6;
        }
        else
        {
        //    HttpContext.Current.Response.Write("编译过程出现了异常");
            DeleteAllFile();
            return -5;//编译过程出现了异常
        }
    }
    //获取采用java编写提交的代码的中的类名,该类名用来给该文件命令,这是java的规则
    private String GetJavaCodeClass(String JavaCode)
    {
        int tmpstart = JavaCode.IndexOf("class", 0);
        int tmpend=JavaCode.IndexOf("{",0);
        if (tmpstart==-1)
        {
          //  HttpContext.Current.Response.Write("你所提交的代码不是JAVA类型的,请选择代码类型");
            return "0";
        }
        String str=JavaCode.Substring(tmpstart+5,tmpend-tmpstart-5).Trim();
        return str;
    }
    //清理垃圾文件,每一次提交完毕之后,将所有产生的垃圾文件进行删除,但是保留代码文件,用于以后让大家学习
    private void DeleteAllFile()
    {
        if (File.Exists(PathNameExe))
        {
            File.Delete(PathNameExe);
        }
        if (File.Exists(PathNameObj))
        {
            File.Delete(PathNameObj);
        }
        if (File.Exists(InputTxt))
        {
            File.Delete(InputTxt);
        }
        if (File.Exists(OutputTxt))
        {
            File.Delete(OutputTxt);
        }
    }
    public String  GetError(int type)
    {
        String ErrorStr = null ;
        switch (type)
        {
            case 0:
                ErrorStr = "代码已经编译成功,但是系统在生成.out文件时,出现异常";
                break;
            case 1:
                ErrorStr = "【提交成功】,恭喜你,已经答对了该题了,请再接再厉,加油";
                break;
            case 2:
                ErrorStr = "代码已经编译成功,但是你的算法中存在逻辑错误。或者你数据变量的范围太小 ,尝试将int"+
                            "改为long。请仔细设计算法逻辑。";
                break;
            case -1:
                ErrorStr = "代码执行的过程中,系统发生了异常。解决方案,尝试重新进行提 交。该错误是由系统引 "+
                           " 起的,如果多次出现同样错误,请报告错误给我:[email protected]";
             break;
            case -2:
                ErrorStr = "代码已经编译成功,在执行的过程中系统出现异常,请稍候提交。";
                break;
            case -4:
                ErrorStr = "编译没有通过,你所提交的代码含有错误。请好好查看一下代码是 否出现了错误或者所选" +
                           "择的编译语言的类型有错。";
                break;
            case -5:
                ErrorStr = "编译过程中,系统出现了异常错误。请稍候进行提交。";
                break;
            case -6:
                ErrorStr = "你所提交的代码不是java类型,却选择了JAVA类型进行编译。请重新  选择语言类型。";
                break;
        }
        return ErrorStr;
    }
}
//该类主要负责处理用户提交的程序使用的执行时间和内存的情况
//主要用于检测用户是否提交了死循环或者恶意大量开辟内存的情况
//由于考虑到一些都是程序设计的初学者,这里就先不进行限制
/*public class  GetProcessRun
{
    private string ProcessName=null;
    private int Memory = 0;//使用内存情况
    private int RunTime = 0;//运行所花费的时间
    public Process[] MyProcess = Process.GetProcesses();
    GetProcessRun(int Memory,int RunTime,String ProcessName)
    {
        this.Memory = Memory;
        this.RunTime = RunTime;
        this.ProcessName = ProcessName;
        MyProcess = Process.GetProcessesByName(ProcessName);
    }
    private double GetMemory()
    {
        return (MyProcess[0].WorkingSet / 1024);
    }
    private double GetRunTime()
    {                
        return MyProcess[0].TotalProcessorTime.TotalMinutes;
    }
}*/


如果大家在使用这类的时候,有疑问,欢迎大家进行评论和交流。我讲尽自己的力量为大家答疑。

你可能感兴趣的:(C++,Web,String,C#,cmd,编译器)