分享一個的c++寫的,模仿awk的框架類CAwkDoc

皇家救星發表於2021-01-10

這是我好多年前,模仿awk寫的。
awk大家都比較熟悉,使用awk處理檔案,讀取檔案,分割欄位這些工作awk自己幫你實現了。
程式設計師只要編寫業務邏輯程式碼,並且awk還提供了很多常用的字串操作函式,可以方便地呼叫,所以使用起來很方便。
但awk指令碼畢竟不適合開發複雜的邏輯,而且它提供的庫函式也有限,不像c++,有很多第三方庫可以呼叫。
於是我就想到了寫一個框架類,把按行讀檔案,分割欄位這些基本功能實現了,只留下業務邏輯供開發人員自由實現


這裡用了策略模式,程式設計師把業務邏輯封裝成為一個策略類(實現IAwkOneDualItr介面)傳給CAwkDoc即可享受CAwkDoc提供的讀檔案功能。
最開始考慮過使用模板方法就行,但又擔心繼承CAwkDoc的程式設計師覆蓋了它的實現,所以覺得還是策略方法好。


這是我之前用CAwkDoc實現的一個小工具:程式碼生成器https://github.com/kingstarer/kingstarer/tree/master/c%2B%2B/feepacker)
當年這個工具給專案組減輕了不少工作量,我同事們當時特別喜歡。
可惜專案現在早就涼了,不然這個工具估計還是在用:)
工具雖然早沒用了,但這個程式碼生成器的思想(程式碼模板替換)我還是蠻喜歡的,前段時間搞java專案,寫了一個curd程式碼生成器,還是套用了這個方法,使用程式碼模板思想。


分享一下CAwkDoc的主要程式碼

AwkBase.h

#pragma once
#include "AwkFunc.h"

class CAwkDoc;
class IAwkOneDualItr
{
public:
    virtual int dualBegin(CAwkDoc &Doc) = 0;
    //返回0代表正常,繼續處理下一條 返回1代表退出文字處理直接到End階段 返回-1代表處理出錯,直接退出  
    virtual int dualOneLine(CAwkDoc &Doc) = 0;
    virtual int dualEnd(CAwkDoc &Doc) = 0;
};

class CAwkOneDualItrBase:public IAwkOneDualItr
{
public:
    virtual int dualBegin(CAwkDoc& Doc)
    {
        return 0;
    }

    virtual int dualEnd(CAwkDoc& Doc)
    {
        return 0;
    }
};

class CAwkDoc
{
public:
    typedef map<string, string> AwkMapType;
    typedef vector<string> AwkVecType;

public:
    CAwkDoc(void);
    CAwkDoc(IAwkOneDualItr* lineopr, const string& filepath);
    virtual ~CAwkDoc(void);
    virtual bool run();

    void setFileName(const string& filepath) 
    { 
        m_filename = filepath; 
    }

    void setDelimer(const string delimer) 
    { 
        m_delimer = delimer; 
    }

    vector<string>& Parts()
    {
        return m_vecParts;
    }

    void setStrParam(const string& paramname, const string& paramvalue);
    string& getStrParam(const string& paramname);

    AwkVecType& getVecParam(const string& paramname);
    AwkMapType& getMapParam(const string& paramname);

public:

    int m_nf;
    int m_nr;
    string m_filename;
    string m_line;
    string m_delimer;
    vector<string> m_vecParts;


    map<string, string> m_strParams;
    map< string, AwkMapType > m_mpParams;
    map< string, AwkVecType > m_vecParams;

public:

    IAwkOneDualItr *m_lineopr;
};

AwkBase.cpp

#include "stdafx.h"
#include "AwkBase.h"

CAwkDoc::CAwkDoc(void)
{
    m_delimer = " ";
    m_nf = m_nr = 0;
    m_lineopr = NULL;
}

CAwkDoc::CAwkDoc(IAwkOneDualItr* lineopr, const string& filepath):
m_lineopr(lineopr), m_filename(filepath)
{
    m_nf = m_nr = 0; 
    m_delimer = " ";
}

CAwkDoc::~CAwkDoc(void)
{
}


bool CAwkDoc::run()
{
    //讀取檔案
    string inparamStr = FileToString(m_filename);


    //將檔案分行
    vector<string> vecLines;
    SplitStr(inparamStr, "\n", vecLines);

    if (vecLines.size() == 0)
    {
        cerr << "ERR: 檔案(" <<  m_filename << ")為空或不存在!" << endl;
        return false;
    }

    assert(m_lineopr != NULL);
    m_lineopr->dualBegin(*this);

    for (size_t i = 0; i < vecLines.size(); i++)
    {
        m_line = vecLines[i];
        if (m_line == "")
        {
            continue;
        }


        //刪除多餘空格(為後面分割做準備)
        string theline = m_line;
        //constrictSpace(theline);

        m_nr++;
        m_nf = SplitStr(theline, m_delimer, m_vecParts);

        if (m_vecParts.size() < 20)
        {
            m_vecParts.resize(20);
        }

        int ret = m_lineopr->dualOneLine(*this);

        //1是正常結束 -1是異常結束
        if ( ret == 1 )
        {
            break;
        }
        else if ( ret == -1 )
        {
            return false;
        }
    }

    m_lineopr->dualEnd(*this);

    return true;
}

void CAwkDoc::setStrParam(const string& paramname, const string& paramvalue)
{
    m_strParams[paramname] = paramvalue;
}

string& CAwkDoc::getStrParam(const string& paramname)
{
    return m_strParams[paramname];
}

相關文章