2017-09-29 30 views
0

我想解析相對簡單的註冊表文件格式,讓我們假設它是純粹的ascii,以舊的REGEDIT4格式保存。我想解析它使用標準的C++正則表達式類或函數(最好不增強)。作爲輸入數據,它可以採取例如樣本文件是這樣的:使用C++正則表達式進行多重匹配

REGEDIT4 

[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0] 

[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0\General] 
"SettingDword"=dword:00000009 
"Setting1"="Some string 1" 
"SettingString2"="my String" 

[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0\Networking] 
"SettingDword2"=dword:00000002 
"Setting2"="Some string 2" 
"SettingString3"="my String2" 

我已經簡要分析 - 掃描多[]可以使用例如cregex_token_iterator類來完成,但是主要的問題是,它是在相反的工作方式,我想要使用它。我想開始匹配這樣的模式:regex re("(\\[.*?\\])"),但令牌迭代器返回所有不匹配的字符串,這對我來說聽起來很傻。

基本上我想匹配第一個整節(\\[.*?\\])(.*?\n\n),然後選擇註冊表路徑,然後鍵入值 - 然後使用正則表達式鍵值對分割。

在C#中編寫像這樣的正則表達式匹配器相對容易,但我更喜歡使用C++,因爲它本地化,沒有性能和組件卸載問題。

回答

0

最後進行交叉分析 - 可以使用regex_search,但搜索需要在發現模式後繼續從下一個char *開始重試。

下面幾乎是在運行時加載.reg文件的完整示例,我使用的是MFC的CString,因爲它比std::string稍微容易使用,並且當前不需要可移植性。

#include "stdafx.h" 
#include <afx.h>    //CFile 
#include "TestRegex.h" 
#include <fstream> 
#include <string> 
#include <regex> 
#include <map> 

CWinApp theApp; 

using namespace std; 
typedef enum 
{ 
    eREG_DWORD = REG_DWORD, 
    eREG_QWORD = REG_QWORD, 
    eREG_BINARY = REG_BINARY, 
    eREG_SZ = REG_SZ 
}eRegType; 

class RegVariant 
{ 
public: 
    eRegType type; 

    union 
    { 
     DWORD dw; 
     __int64 qw; 
    }; 

    CStringA str; 
}; 



class RegKeyNode 
{ 
public: 
    // Paths to next nodes 
    map<CStringA, RegKeyNode> keyToNode; 

    // Values of current key 
    map<CStringA, RegVariant> keyValues; 
}; 

map<HKEY, RegKeyNode> g_registry; 

int char2int(char input) 
{ 
    if (input >= '0' && input <= '9') 
     return input - '0'; 
    if (input >= 'A' && input <= 'F') 
     return input - 'A' + 10; 
    if (input >= 'a' && input <= 'f') 
     return input - 'a' + 10; 
    return 0; 
} 

void hexToBin(const char* hex, CStringA& bin, int maxSize = -1) 
{ 
    int size = (strlen(hex) + 1)/ 3; 

    if(maxSize != -1 && size > maxSize) 
     size = maxSize; 

    unsigned char* buf = (unsigned char*)bin.GetBuffer(size); 
    for(int i = 0; i < size; i++) 
     buf[i] = char2int(hex[ i*3 ]) * 16 + char2int(hex[i * 3 + 1]); 

    bin.ReleaseBuffer(); 
} 


int main() 
{ 
    HMODULE hModule = ::GetModuleHandle(nullptr); 
    AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0); 


    // 
    // Load .reg file. 
    // 
    CString fileName = L"test1.reg"; 
    CStringA file; 
    CFile cfile; 

    if (cfile.Open(fileName, CFile::modeRead | CFile::shareDenyNone)) 
    { 
     int len = (int)cfile.GetLength(); 
     cfile.Read(file.GetBuffer(len), len); 
     file.ReleaseBuffer(); 
    } 
    cfile.Close(); 
    file.Replace("\r\n", "\n"); 

    const char* pbuf = file.GetBuffer(); 
    regex reSection("\\[(.*?)\\]([^]*?)\n\n"); 
    regex reLine("^\\s*\"(.*?)\"\\s*=\\s*(.*)$"); 
    regex reTypedValue("^(hex|dword|hex\\(b\\)):(.*)$"); 
    regex reStringValue("^\"(.*)\"$"); 
    cmatch cmSection, cmLine; 

    // 
    // For each section: 
    // 
    // [registry path] 
    // "value1"="value 1" 
    // "value2"="value 1" 
    // 
    while(regex_search(pbuf, pbuf + strlen(pbuf), cmSection, reSection)) 
    { 
     CStringA path = cmSection[1].str().c_str(); 
     string key_values = cmSection[2].str(); 
     const char* pkv = key_values.c_str(); 

     int iPath = 0; 
     CStringA hkeyName = path.Tokenize("\\", iPath).MakeUpper(); 

     RegKeyNode* rnode; 
     if(hkeyName.Compare("HKEY_LOCAL_MACHINE") == 0) 
      rnode = &g_registry[HKEY_LOCAL_MACHINE]; 
     else 
      rnode = &g_registry[HKEY_CURRENT_USER];  // Don't support other HKEY roots. 

     // 
     // Locate path where to place values. 
     // 
     for(; hkeyName = path.Tokenize("\\", iPath);) 
     { 
      if(hkeyName.IsEmpty()) 
       break; 

      rnode = &rnode->keyToNode[hkeyName]; 
     } 

     // 
     // Scan "key"="value" pairs. 
     // 
     while(regex_search(pkv, pkv+strlen(pkv), cmLine, reLine)) 
     { 
      CStringA key = cmLine[1].str().c_str(); 
      string valueType = cmLine[2].str(); 
      smatch cmTypeValue; 
      RegVariant* rvValue = &rnode->keyValues[key]; 

      // 
      // Extract type and value. 
      // 
      if(regex_search(valueType, cmTypeValue, reTypedValue)) 
      { 
       string type = cmTypeValue[1].str(); 
       string value = cmTypeValue[2].str(); 

       if(type == "dword") 
       { 
        rvValue->type = eREG_DWORD; 
        rvValue->dw = (DWORD)strtoul(value.c_str(), 0, 16); 
       } 
       else if (type == "hex(b)") 
       { 
        rvValue->type = eREG_QWORD; 
        rvValue->qw = 0; 
        if(value.size() == 8 * 2 + 7) 
        { 
         CStringA v; 
         hexToBin(value.c_str(), v, sizeof(__int64)); 
         rvValue->qw = *((__int64*)v.GetBuffer()); 
        } 
       } else //if (type == "hex") 
       { 
        rvValue->type = eREG_BINARY; 
        hexToBin(value.c_str(), rvValue->str); 
       } 

      } else if(regex_search(valueType, cmTypeValue, reStringValue)) 
      { 
       rvValue->type = eREG_SZ; 
       rvValue->str = cmTypeValue[1].str().c_str(); 
      } 

      pkv = cmLine[2].second; 
     } //while 

     pbuf = cmSection[2].second; 
    } //while 


    return 0; 
}