日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OnlineJudge 离线题库采集

發(fā)布時間:2023/12/31 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OnlineJudge 离线题库采集 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

????過段時間要把以前的OJ換掉,我負責VirtualJudge的部分。需要用C與PHP寫一個Linux下的VJudge。

????在此之前,將以前寫給自己學弟學妹用的OJ離線題庫的采集程序改進了一下。支持國內(nèi)一些知名高校的OJ,為之后VJudge的開發(fā)練練手,熟悉下各個OJ的結構,免去以后再在LINUX上進行一些繁瑣的測試。

????題目的采集沒有使用任何OJ的API,直接采取從HTML頁面采集數(shù)據(jù)并處理的方式。下載HTTP文件使用的是WinINet函數(shù)集,用起來比CURL還方便。正則表達式使用的ATL庫里的regex。題目的儲存使用的文件進行儲存。別看一個OJ就有幾千道題,文件結構訪問的速度卻是相當?shù)乜臁R驗樽ト〕鰜淼念}目有大量的HTML標簽,先要全部去掉非常地困難(一些題目有不同的格式與鏈接標簽,甚至有一些題目是關于標記語言的題目)。因為我現(xiàn)在做的是離線的題庫,于是將這些標簽保留寫來,利用HTML的方式顯示我采集的題目。


????目前做了六個OJ:

????1、bnu(北京師范大學OJ):這個OJ我覺得是國內(nèi)用戶體驗做得最好的一個OJ,自己OJ的題目很豐富(含有較多不錯的中文),VOJ的功能也完美地融合在自己的OJ中。

????2、hdu(杭州電子科技大學OJ):擁有國內(nèi)最強判題機群,國內(nèi)各大算法競賽都選在杭電OJ舉行。

????3、neu(成都東軟學院OJ):很多人可能都不知道這OJ,也是國內(nèi)少數(shù)登錄需要驗證碼的奇葩OJ,以至于VOJ想支持它都困難,簡單題爆多,歡迎來擼。我母校嘛,必須有,雖然我亞洲區(qū)牌都沒拿到個,學校最高也就個銅。補習班性質(zhì)的比賽嘛,二本學校的學生都不想把耍的時間花在覺得苦逼的事情上,我能拿著塑料堅持那么久也是NB了。該OJ即將在今年更換新的系統(tǒng),判題內(nèi)核、數(shù)據(jù)管理、界面、以及VOJ都由我們的老成員完成。希望以后學校的騷年能取得好成績--wchrt。

????4、poj(北京大學OJ):搞ICPC的騷年都知道,國內(nèi)最為知名的OJ之一。

????5、vijos(高效信息學在線評測系OJ):里面全是中文題哦,小心有大量的小學生,分分鐘虐爆你的小學生。

????6、zoj(浙江大學OJ):國內(nèi)起步最早的OJ之一,但我基本沒怎么用過這個OJ。


????下面根據(jù)各oj分別列出了獲取題目內(nèi)容與標題的正則表達式:

????????ojnum=0;cbox->AddString("bnu");ojurl[ojnum]="http://www.bnuoj.com/bnuoj/problem_show.php?pid=";ojgetstr[ojnum].allcontent="{<div?id=\"showproblem\">(.|\n)*?<div?id=\"one_content_base\">}";ojgetstr[ojnum].title="<div?id=\"showproblem\.*?<h1.*?>{.*?}</h1>";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("hdu");ojurl[ojnum]="http://acm.hdu.edu.cn/showproblem.php?pid=";ojgetstr[ojnum].allcontent="{<h1(.|\n)*?Note</a>}";ojgetstr[ojnum].title="<h1.*?>{.*?}</h1>";ojgetstr[ojnum].iscode=false;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("neu");ojurl[ojnum]="http://acm.nsu.edu.cn/JudgeOnline/problem.php?id=";ojgetstr[ojnum].allcontent="{<div?id=main(.|\n)*?Sample?Output(.|\n)*?BBS(.|\n)*?</a>}";ojgetstr[ojnum].title="<title.*?>{.*?}</title>";//目前不需要把內(nèi)容信息分開,就不正則詳細的題目內(nèi)容/*ojgetstr[ojnum].tim="Time?Limit:{.*?}&nbsp";ojgetstr[ojnum].mem="Memory?Limit:{.*?}<br>";ojgetstr[ojnum].des=">Description</h2>.*?<div.*?>{.*?}</div>";ojgetstr[ojnum].input=">Input</h2>.*?<div.*?>{.*?</div>.*?}</div>";ojgetstr[ojnum].output=">Output</h2>.*?<div.*?>{.*?}</div>";ojgetstr[ojnum].sinput=">Sample?Input</h2>.*?{<pre>(.|\n)*?</pre>}";ojgetstr[ojnum].soutput=">Sample?Output</h2>.*?{<pre>(.|\n)*?</pre>}";*/ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("poj");ojurl[ojnum]="http://poj.org/problem?id=";ojgetstr[ojnum].allcontent="{<div?class=\"ptt\"(.|\n)*?Discuss</a>}";ojgetstr[ojnum].title="<div?class=\"ptt\".*?>{.*?}</div>";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=49;//poj最多只允許短時間訪問49道題ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("vijos");ojurl[ojnum]="https://vijos.org/p/";ojgetstr[ojnum].allcontent="{<div?class=\"pcontent\">(.|\n)*}<h4";ojgetstr[ojnum].title="<div?class=\"content\">.*?</span>{.*?}<div";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("zoj");ojurl[ojnum]="http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=";ojgetstr[ojnum].allcontent="{<div?id=\"content_body\">(.|\n)*</div>}";ojgetstr[ojnum].title="<div?id=\"content_body\">.*?>.*?>{.*?}</span>";ojgetstr[ojnum].iscode=false;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;


因為不同的OJ網(wǎng)站所使用的編碼格式不同,我使用的是ansi,所以要把一些使用utf-8的網(wǎng)頁轉換為ansi,下面是轉換的代碼:

static?void??UTF8toANSI(CString?&strUTF8) {UINT?nLen?=?MultiByteToWideChar(CP_UTF8,NULL,strUTF8,-1,NULL,NULL);WCHAR?*wszBuffer?=?new?WCHAR[nLen+1];nLen?=?MultiByteToWideChar(CP_UTF8,NULL,strUTF8,-1,wszBuffer,nLen);wszBuffer[nLen]?=?0;nLen?=?WideCharToMultiByte(936,NULL,wszBuffer,-1,NULL,NULL,NULL,NULL);CHAR?*szBuffer?=?new?CHAR[nLen+1];nLen?=?WideCharToMultiByte(936,NULL,wszBuffer,-1,szBuffer,nLen,NULL,NULL);szBuffer[nLen]?=?0;strUTF8?=?szBuffer;delete?[]szBuffer;delete?[]wszBuffer; }


????使用WinINet函數(shù)集的CInternetSession與CHttpFile下載HTTP文件,那hdu作為例子

hdu的1001題的地址是:"http://acm.hdu.edu.cn/showproblem.php?pid=1001"

這里的http://acm.hdu.edu.cn/showproblem.php是hdu的題目PHP文件,我們需要以GET的方式請求pid=1001的數(shù)據(jù)。對于hdu的其他題目,我們只需把pid的值設置成其他的值即可。


????????//獲取GET方式獲取題目的HTML頁面CInternetSession?intsess;CHttpFile?*phtfile?=?NULL;phtfile?=?(CHttpFile?*)intsess.OpenURL(url);UINT?nfilelen?=?(UINT)?phtfile->GetLength();CString?strhtml;CString?buffer;UINT?dw=0;while(dw<nfilelen)//將數(shù)據(jù)轉入strhtml處理{dw+=phtfile->ReadString(buffer);strhtml+=buffer;dw++;}//使用正則表達式提取數(shù)需要的內(nèi)容data->all=strhtml;getcontent(ojgetstr->allcontent,strhtml,data->allcontent);//去除題目頁面的多與信息getcontent(ojgetstr->title,strhtml,data->title);/*getcontent(ojgetstr->tim,strhtml,data->tim);getcontent(ojgetstr->mem,strhtml,data->mem);getcontent(ojgetstr->des,strhtml,data->des);getcontent(ojgetstr->input,strhtml,data->input);getcontent(ojgetstr->output,strhtml,data->output);getcontent(ojgetstr->sinput,strhtml,data->sinput);getcontent(ojgetstr->soutput,strhtml,data->soutput);*/if(ojgetstr->iscode){UTF8toANSI(data->allcontent);UTF8toANSI(data->title);/*UTF8toANSI(data->tim);UTF8toANSI(data->mem);UTF8toANSI(data->des);UTF8toANSI(data->input);UTF8toANSI(data->output);UTF8toANSI(data->sinput);UTF8toANSI(data->soutput);*/}if(data->allcontent.GetLength()<5||data->title.GetLength()<1){return?0;}//將處理后的數(shù)據(jù)寫入到文件中CFile?file;if(!file.Open("c:\\ojdata\\"+data->oj+"\\"+data->id,CFile::modeWrite)){if(!file.Open("c:\\ojdata\\"+data->oj+"\\"+data->id,CFile::modeCreate|CFile::modeWrite)){return?0;}}CArchive?ar(&file,CArchive::store);ar<<data;ar.Close();file.Close();


????因為每個OJ的題目都有幾千道,不可能每次打開軟件都去遍歷那么幾千個文件,效率太低而且容易出錯。因此我將每個題目的ID和標題都提取出來,放到一個文件中記錄,用于題目的引索。

引索的結構是:題目數(shù)量、id1、標題1、id2、標題2、id3...的格式,每個OJ一個表。

下面是儲存記錄的代碼,使用序列化儲存:

????????CFile?file;if(!file.Open("c:\\ojdata\\"+oj+"\\pinfo",CFile::modeWrite)){if(!file.Open("c:\\ojdata\\"+oj+"\\pinfo",CFile::modeCreate|CFile::modeWrite)){AfxMessageBox("寫入出錯");return?1;}}CArchive?ar(&file,CArchive::store);ar<<that->infonum;for(int?i=0;i<that->infonum;i++){ar<<(&that->problemarr[i]);}ar.Close();file.Close();//統(tǒng)計題目下載成功與失敗str.Format("SECC:%d??FAIL:%d",that->infonum,totalnum-50-that->infonum);


hdu的:


全是中文題目的OJ,不錯不錯:


水水更健康:

????基本上題目的采集工作到此結束。以后做VOJ的時候再將各個部分正則出來。

因為網(wǎng)絡環(huán)境的因素,OJ題目的訪問速度不一定很快,這里可以用開多個線程進行下載,以及優(yōu)化題目的下載和處理,因為我可以直接掛在我的服務器上下載,所以就一條線程下載處理完了。我用的電信50M的寬帶(坑爆,說是50M,上行只有不到2M,電信太煎餅了,一個月169還不包含短信費,80端口封完喊還推薦我開3000一個月的商務寬帶)大概下載一個OJ的所有題目10多分鐘,我直接6個OJ一起下載的。不想等待的朋友可以直接在附件下載我采集好的題目包,把它解壓到到C盤即可。


????采集到了題目,怎么看呢?肯定不能直接給人看,一堆標記語言煩死了。WINDOWS自帶了瀏覽器控件,直接使用它即可,我使用了兩種方式,一種是對話框上的HTML控件,可能是我的原因但是這個控件不穩(wěn)定, 在一些電腦上老加載出錯。



????于是我另外用了CDHtmlDialog。這直接是個HTML的對話框,每次把題目的本地地址給他后讓其Navigate即可。由于我題目是儲存的一個problemdata結構體,含有一些其他的信息。打開題目前需要把要顯示的題目提取出來,重新生成一個HTML文件,然后再讓HTML對話框打開它。

????題目的顯示過程:

bool?ProblemList::opensafeproblem(CString?oj,CString?pid) {CFile?file;if(!file.Open("c:\\ojdata\\"+oj+"\\"+pid,CFile::modeRead)){return?false;}CArchive?ar(&file,CArchive::load);problemdata?*data;ar>>data;ar.Close();file.Close();HtmlContent?*contentdlg=new?HtmlContent;if(!contentdlg->setdata(*data)){AfxMessageBox("文件打開失敗");return?false;}contentdlg->Create(IDD_DIALOG_HTML);contentdlg->ShowWindow(SW_SHOW);contentdlg->SetWindowTextA(pid);return?true; }BOOL?HtmlContent::OnInitDialog() {CDHtmlDialog::OnInitDialog();this->SetHostFlags(DOCHOSTUIFLAG_NO3DBORDER?|?DOCHOSTUIFLAG_FLAT_SCROLLBAR);//將題目轉化為HTML文件并在本地打開顯示CFile?*f=new?CFile;if(!f->Open("c:\\ojdata\\"+data->oj+"\\"+data->id+".html",CFile::modeCreate|CFile::modeWrite)){AfxMessageBox("打開失敗");this->CloseWindow();}f->Write(data->allcontent,data->allcontent.GetLength());f->Close();this->Navigate("c:\\ojdata\\"+data->oj+"\\"+data->id+".html");return?TRUE;??//?除非將焦點設置到控件,否則返回?TRUE }

????整個離線題庫就是這樣,需要支持其他OJ只要改改正則和題號即可,對于一些沒法直接獲取到題目的OJ要做另外的處理,uestc的新OJ就需要另外的方式獲取題目內(nèi)容。

????采集程序源碼

????采集程序

????OJ題庫下載

轉載于:https://blog.51cto.com/wchrt/1606066

總結

以上是生活随笔為你收集整理的OnlineJudge 离线题库采集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。