使用C 等级进行多匹配

Using C++ regex for multi match

本文关键字:使用      更新时间:2023-10-16

我想解析相对简单的注册表文件格式,让我们假设它是普通的ascii,以旧的regedit4格式保存。我想使用标准的C 正则函数或功能(最好无提升)对其进行解析。作为输入数据,可以以这样的示例文件为例:

REGEDIT4
[HKEY_LOCAL_MACHINESOFTWAREMyCompanyConfigurationDatav1.0]
[HKEY_LOCAL_MACHINESOFTWAREMyCompanyConfigurationDatav1.0General]
"SettingDword"=dword:00000009
"Setting1"="Some string 1"
"SettingString2"="my String"
[HKEY_LOCAL_MACHINESOFTWAREMyCompanyConfigurationDatav1.0Networking]
"SettingDword2"=dword:00000002
"Setting2"="Some string 2"
"SettingString3"="my String2"

我已经简要分析了 - 可以使用例如cregex_token_iterator类扫描多个[],但是主要问题是它以相反的方式工作,我想使用它。我想开始这样的匹配模式:regex re("(\[.*?\])"),但是令牌迭代器返回所有不匹配的字符串,对我来说听起来很愚蠢。

基本上,我想匹配整个部分(\[.*?\])(.*?nn),然后首先访问注册表路径,然后接下来 - 然后使用Regex键值对分开。

在C#中,像这样编写Regex Matcher相对容易,但我更喜欢与C 一起使用,因为它是本地的,没有性能和组装卸载问题。

终于进行了交叉分析 - 可以使用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("rn", "n");
    const char* pbuf = file.GetBuffer();
    regex reSection("\[(.*?)\]([^]*?)nn");
    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;
}