91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于C++如何編寫一個文章生成器

發布時間:2023-03-17 10:17:22 來源:億速云 閱讀:232 作者:iii 欄目:開發技術

這篇“基于C++如何編寫一個文章生成器”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“基于C++如何編寫一個文章生成器”文章吧。

    1.概況

    由用戶輸入啟動詞,根據語料庫中統計的詞語前后綴關系,自動生成一片新的文章。

    比如:春天來了,大地媽媽穿上了碧綠的衣裳。嫩綠的小草從地下探出頭來,陶醉在美麗的春天里。

    前后綴關系:[前綴,后綴]。上面這段話的前后綴關系有:[春天,來/里],[天來,了],[天里,。],[來了,,]等。

    說明:

    啟動詞:用戶輸入的一個詞,由這個詞開始生成文章所有內容。

    前/后綴:一個詞前后連續的n個字符。比如前綴為“春天”,由例句中得到后綴可為“來”或“里”,即表示一種語言的前后關系。

    2.基本要求

    1.準備語料庫:準備相關文章,存為文件。利用程序讀取文章內容,獲取文章語句中詞語的前后關系,即語料庫。語料庫的豐富程度由文章的數量決定,語料庫又決定程序運行的時間和生成的文章質量。

    2.構建前后綴關系:根據語料庫,依據設定的前后綴長度,構建字詞的前后綴關系。

    3.生成文章:用戶輸入啟動詞,根據啟動詞為前綴生成后綴得到文段,再根據文段生成新的前綴,以新前綴生成新后綴以此類推,得到一片文章。

    4.應盡量避免循環:有時語料庫中可能出現類似“為所欲為”的接龍結構,造成死循環,同時生成的內容也沒有了意義。

    5.輸入輸出形式:

    //輸入:
        2    //前綴詞長度
        2    //后綴詞長度
        春天    //啟動詞
    //輸出:
        [一篇文章]

    3.程序分析

    3.1 文件流讀寫

    讀文件:從多篇文章中讀取文件內容為字符串,以前/后綴的長度遍歷獲取前/后綴,并建立前后綴關系。

    寫文件:為觀察程序執行情況,將前/后綴字符對和生成的文章寫入文件。

    3.2 建立前后綴關系

    當需要在兩種數據間建立一種關系時,可以使用結構化數據進行存儲,比如建立前后綴關系可以采用字典類結構進行存儲,C++也有相應的頭文件。

    除此之外,還可以將其抽象為一種類,可以定制類的行為和結構。這里選擇自建一個類進行存儲。

    類設計:

    • 一個類記錄一個前綴和它的所有后綴,

    • 記錄后綴的出現次數

    • 記錄后綴的個數

    class wordpair{
        private:
            char **suffix    //后綴字符串數組,一個后綴存為一個字符串
            int *freq        //一個后綴出現的次數
        public:
            char *prefix    //前綴字符串,聲明為公共成員,方便外部查找
            int length        //記錄后綴的個數
    }

    3.3 字符串切片

    在C++的頭文件中,可以使用string類型代替char類型的字符串,而且對于字符串的操作也更方便。比如

    string str1 = "abcd";
    string str2 = "efghijk";
    string str3 = str1 + str2;    // = “abcdefghijk”; 字符串拼接
    string str4 = str3.substr(3,2);    // = "de"; 從下標為3的字符開始,截取長度為2的子字符串

    以前一直覺得C語言和C++處理字符串很麻煩,現在倒覺得還是很方便的。

    3.4 變長數組

    C語言和C++中,基礎的數組長度相對固定,但也不是不能改變,只是相對麻煩一些。在這個程序中,一個wordpair只存儲一個前綴和它的后綴們,所以需要創建一個wordpair類型的列表來存儲全部的前后綴。

    我用的方法是來回地復制

    int main(){
        int len;
        int list[len];    //假設有一個長度為len的整型數組
        int p[len+1];    //開辟一個len+1個整型長度的空間
        //    把 list 復制到 p,然后
        list = new int[len+1];    //將list長度+1
        //把 p 復制過來
    }

    4.代碼實現

    4.1 函數:數組加長

    由于數組加長在程序中多次調用,且需要增長的數組各不相同,所以在這里我定義了一個函數模板,以盡可能少的代碼完成相同的任務。

    template<class T>
    T *append2list(T *list, T t, int len){
        T copy[len + 1];            // 用于備份的空間
        for(int i=0; i<len; i++){
            copy[i] = list[i];}
        copy[len] = t;                //在末尾增加元素
        len++;
        list = new T[len];            //變長
        for(int i=0; i<len; i++){    //拷貝回來
            list[i] = copy[i];}
        return list;
    }

    4.2 類wordpair定義

    首先是類成員,應該有:

    class Wordpair
    {
        private:
            string *suffix;    //后綴列表,一個前綴可能對應多個后綴 
            int   *freq;    // 整型數組,依此記錄后綴的頻率
        public:
            string prefix;    // 前綴 
            int length;        // 記錄長度 , 一個前綴對應size個后綴 
            Wordpair(string prefix, string suffix){    //構造函數
                this->prefix = prefix;
                this->suffix = new string[1];
                this->suffix[0] = suffix;
                this->freq = new int[1];
                this->freq[0] = 1;
                this->length = 1;
            }
            Wordpair(){                                //構造函數
                this->prefix = "",
                this->suffix = new string[1];
                this->suffix[0] = "";
                this->freq = new int[1];
                this->freq[0] = 0;
                this->length = 0;
            }
            /* 判斷這個后綴是否已經有記錄,有返回下標,沒有則返回-1 */
            int hasRecorded(string word){}
            
            /* 添加一個后綴 */
            bool push(string word){}
            
            /* 找出出現次數最多的后綴的下標,采用更可信的后綴 */
             string maxFrequency(){}
            
            /* 轉化為字符串,方便輸出 */
            string to_String()const{}
            /* 重載賦值運算符,方便與其他類型的列表共用函數 */
            Wordpair& operator=(Wordpair &pair){}
    };

    除此之外,還可以重載輸出運算符<<,便于調試時在函數中輸出wordpair值:

    ostream& operator<<(ostream& out, const Wordpair& w){
        out<<w.to_String();
        return out;
    }

    4.3 函數:讀取文件

    程序運行時,需要讀取文件為字符串,當文件較多時把這個功能抽象出來,調用很方便。

    // 讀文件 
    string getfile(char *path){
      string alticle = "";            //初始化字符串
      ifstream fin(path, ios::in);    //打開文件
      if(!fin.is_open()){
        cout<<"文件讀取錯誤!"<<endl;
        return NULL;
      }
      string buffer;
      while(getline(fin,buffer)){        //讀取
        alticle.append(buffer);            //新的行添加到alticle尾部
      }
      fin.close();
      return alticle;
    }

    4.4 函數:寫入文件

    主要是寫入生成的字符對,方便調試

    // 寫文件,記錄詞組對 
    void exportData(Wordpair *pairlist, int len, int prelen, int suflen){
        char path[32];
        sprintf(path,"./word-pairs(%dx%d).txt",prelen,suflen);
        ofstream fout(path, ios::out);
        for(int i=0; i<len; i++){
            fout<<pairlist[i];        //在這里就體現了重載<<運算符的好處
        }
        fout.close();
        cout<<"詞組對已經寫入文件< "<<path<<" >"<<endl; 
    }

    4.5 核心函數:字符串分割

    讀取到文件后,將字符串從下標0開始,讀取前綴+后綴的長度,然后從1開始讀取前綴+后綴的長度。循環的次數應該是字符串總長度 - (前綴長度+后綴長度 -1),以保證下標不會溢出。

    Wordpair *alticle2Wordpair(Wordpair *pairlist, int &length,string alticle, int prefix_len, int suffix_len){
        for(int i=0; i<alticle.length()/2-prefix_len-suffix_len+1; i++){
            bool hasrecord = false;
            string prefix=alticle.substr(i*2,prefix_len*2);                // i為什么要×2?因為在devcpp中發現一個中文字符相當于兩個英文字符,不乘2會亂碼。 
            string suffix=alticle.substr((i+prefix_len)*2,suffix_len*2);
            for(int j=0;j<length;j++){
                if(pairlist[j].prefix == prefix){    // 如果已經有了這個前綴,則添加后綴 
                    pairlist[j].push(suffix);
                    hasrecord = true;
                    break;
                }
            }
            if(!hasrecord){                            //    沒有這個前綴則詞組對列表長度增加 
                Wordpair pair(prefix, suffix);
                pairlist = append2list(pairlist, pair, length);
                length++;
            }
        }
        return pairlist;
    }

    在此基礎上,對每次讀文件都進行一次,就能獲取全部文件的字符對。

    4.6 核心函數:文章拼接

    得到語料庫之后,需要根據語料庫拼接出文章。我這里采用的方法有點問題,當完全防止出現循環文本的時候,文章過短,當放開一點對循環文本的時候,循環文本總是出現,算法上想不通。希望有大佬提供一點思路。

    // 判斷前綴是否在列表內,有則返回下標,沒有則返回-1
    int hasrecord(Wordpair *pairlist, int len, string preword){
        for(int i=0; i<len; i++){
            if(preword == pairlist[i].prefix){
                return i;
            }
        }
        return -1;
    }
    // 拼接文章 
    void createAlticle(Wordpair *pairlist, int len, string startword, int prefix_len, int suffix_len){
        string preword = startword;
        int i=0;
        int index = hasrecord(pairlist, len, preword);
        string alticle = preword;
        int alticle_len = prefix_len;            //長度(中文字符標準) 
        while(index != -1){
            string newword = pairlist[index].maxFrequency();
            // 避免循環 
            if(alticle.find(newword)==string::npos    //表示這個前綴沒有在文章中出現過 
    //         || alticle_len - alticle.rfind(newword) > 600    //表示相同的詞之間最少間隔多少。加上這個條件后有循環,注釋后文章顯著變短 
             ){
                alticle.append(pairlist[index].maxFrequency());
                alticle_len += suffix_len;
                preword = alticle.substr((alticle_len-prefix_len)*2, alticle_len*2);}
            else{
                preword = pairlist[index+1].maxFrequency();
            }
            index = hasrecord(pairlist, len, preword);
        }
        cout<<alticle<<endl;
        ofstream fout(CREATE_ALTICLE, ios::out);
        fout<<alticle;
        fout.close();
        cout<<"文章寫入文件 < "<<CREATE_ALTICLE<<" >"<<endl;
    }

    以上就是關于“基于C++如何編寫一個文章生成器”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    c++
    AI

    大邑县| 墨竹工卡县| 如东县| 南丰县| 普兰店市| 上犹县| 和硕县| 巴林右旗| 乌拉特中旗| 德江县| 灵宝市| 阜新市| 手机| 吴川市| 太谷县| 洞口县| 青田县| 黑水县| 玉环县| 鹿邑县| 和平区| 宜兴市| 兴业县| 西乡县| 明光市| 偃师市| 连州市| 宾川县| 叶城县| 开鲁县| 桃园县| 武定县| 简阳市| 武汉市| 三明市| 巴林左旗| 马公市| 吉隆县| 大足县| 商丘市| 策勒县|