How to parse a text file into variables using C ++ regex?

Please help me fulfill my dreams and turn this sequence into a meaningful result. :)

See regex in action, it works !: http://regex101.com/r/iM4yN2/1 Now I only need to know how to use it. If I could fit this into a multidimensional array eg. configFile [0] [0] = [Tuner] that will work. Or, if I can turn that into a comma separated list, I could parse it again and put it into arrays and finally into separate variables. You don't need to specify how to assign the variables anyway, I'll create another question if I really need help with this. Basically I need help using the regex functions and outputting data to the SOME variable, where I can access various texts on either side of the = sign in the string.

regular expression:

^[\t ]*(.*?)\s*=[\t ]*(.*?)(#.*)?$

      

test line:

    ### MODULES ###
Tuner         =  
 PitchDetector = 0
PhaseLocker   = 0
FileOutput    = 1

### FILE MANAGER ###
RenameFile_AvgFreq  =  dfgsdfg dsf gdfs g #gdrgk
RenameFile_NoteName = 0
    RenameFile_Prefix   = "The String Is Good"
RenameFile_Suffix   = ""
OutputFolder        = "..\Folder\String\"

### PITCH DETECTOR ###
AnalysisChannel = 1  #int starting from 1
BlockSize             = 8  #power of 2
Overlap               = 16 #power of 2
NormalizeForDetection = 0

### TUNER ###
Smoothing = 0.68
Envelope  = 0.45

### PHASELOCKER ###
FFTSize    = 1024 #powert of 2
FFTOverlap = 54687
WindowType = 0
MaxFreq    = 5000

      

my variables:

//Modules
bool Tuner;
bool PitchDetector;
bool PhaseLocker;
bool FileOutput;

//File Manager
bool RenameFile_AvgFreq;
bool RenameFile_NoteName;
std::string RenameFile_Prefix;
std::string RenameFile_Suffix;
std::string OutputFolder;

//Pitch Detector
int AnalysisChannel;
int BlockSize;
int Overlap;
bool NormalizeForDetection;

//Tuner
float Smoothing;
float Envelope;

//Phaselocker
int FFTSize;
int FFTOverlap;
int FFTWindowType;
float FFTMaxFreq;

      

final notes: I've been looking at C ++ regex functions for a long time ... very confusing stuff. I know how to do this in python without having to think twice.

+3


source to share


2 answers


Another way to do it with regex_iterator:

#include <regex>
using std::regex;
using std::sregex_iterator;

void CreateConfig(string config)
{
    //group 1,2,3,4,5 = key,float,int,string,bool
    regex expr("^[\\t ]*(\\w+)[\\t ]*=[\\t ]*(?:(\\d+\\.+\\d+|\\.\\d+|\\d+\\.)|(\\d+)|(\"[^\\r\\n:]*\")|(TRUE|FALSE))[^\\r\\n]*$", std::regex_constants::icase);
    for (sregex_iterator it(config.begin(), config.end(), expr), itEnd; it != itEnd; ++it)
    {
        if ((*it)[2] != "") cout << "FLOAT -> " << (*it)[1] << " = " <<(*it)[2] << endl;
        else if ((*it)[3] != "") cout << "INT -> " << (*it)[1] << " = " <<(*it)[3] << endl;
        else if ((*it)[4] != "") cout << "STRING -> " << (*it)[1] << " = " <<(*it)[4] << endl;
        else if ((*it)[5] != "") cout << "BOOL -> " << (*it)[1] << " = " << (*it)[5] << endl;
    }
}

int main()
{   
    string s = "what = 1\n: MODULES\nFileOutput = \"on\" :bool\nPitchDetector = TRuE :bool\nTuner = on:bool\nHarmSplitter = off:bool\nPhaseLocker = on\n\nyes\n junk output = \"yes\"\n\n: FILE MANAGER\nRenameFile  AvgFreq  = 1 \nRenameFile_NoteName = 0 :bool\nRenameFile_Prefix   = \"The Strin:g Is Good\" :string\nRenameFile_Suffix   = \"\":string\nOutputFolder        = \"..\\Folder\\String\\\" :relative path\n\n: PITCH DETECTOR\nAnalysisChannel       = 1  :integer starting from 1\nBlockSize             = 8  :power of 2\nOverlap               = 16 :power of 2\nNormalizeForDetection = 0  :bool\n\n: TUNER\nSmoothing = 0.68 :float\nEnvelope  = 0.45 :float\n\n: PHASE LOCKER\nFFTSize    = 1024  :power of 2\nFFTOverlap = 54687 :power of 2\nWindowType = 0     :always set to 0\nMaxFreq    = 5000  :float";
    CreateConfig(s);

    return 0;
}

      

Let it break. The regex expression I created uses the ^ regexy stuff here $ format element so that each line of text is treated separately: ^ = start of line, $ = end of line. The regular expression looks for: variable_name = decimal OR number OR string OR (true OR false). Since each type is stored in its own group, we know what type each match will have.

To explain the for loop, I'll write the code in several different ways.



//You can declare more than one variable of the same type:
for (sregex_iterator var1(str.begin(), str.end(), regexExpr), var2); var1 != var2; var1++)

//Or you can delcare it outside the for loop:
sregex_iterator var1(str.begin(), str.end(), regexExpr);
sregex_iterator var2;
for (; var1 != var2; var1++)

//Or the more classic way:
sregex_iterator var1(str.begin(), str.end(), regexExpr);
for (sregex_iterator var2; var1 != var2; var1++)

      

Now for the body of the for loop. It says, "If group2 is not empty, print group 2, which is a floating point. If gorup3 is not empty, print group 3, which is an int. If group4 is not empty, print group 4, which is a string. If group5 is not empty, print group5, which is bool Inside the loop, the syntax is:

//group0 is some kind of "currently evaluating" string plus group matches.
//group1 is my key group
//group2/3/4/5 are my values groups float/int/string/bool.
theString = (*iteratorVariableName)[groupNumber]

      

+1


source


Include the following:

#include <string>
#include <regex>

      

Declare string and regex type:

std::string s;
std::regex e;

      

In your main function, assign the string and regex variables and call the regex function (you can assign variables when you declare them):

int main()
{
    s="i will only 349 output 853 the numbers 666"
    e="(\\d+)"
    s = std::regex_replace(s, e, "$1\n", std::regex_constants::format_no_copy);

    return 0;
}

      

Notice how I am returning the results back to the string (s). You can of course use a different string to store the result. "Std :: regex_constants :: format_no_copy" is a flag that tells the regex function to print only "substrings" or wildcard matches. Also notice how I use the double slash on "\ d +". Try double slashes if your regex pattern doesn't work.

To find key / value pairs with regex eg. "BlockSize = 1024", you can create a template, for example:

BlockSize\s*=\s*((?:[\d.]+)|(?:".*"))

      



in C ++ you can create this regex pattern with:

expr = key+"\\s*=\\s*((?:[\\d.]+)|(?:\".*\"))";

      

and return the match with:

config = std::regex_replace(config, expr, "$1", std::regex_constants::format_no_copy);

      

and combine it all into a function with the option to return a default value:

std::string Config_GetValue(std::string key, std::string config, std::string defval)
{
    std::regex expr;
    match = key+"\\s*=\\s*((?:[\\d.]+)|(?:\".*\"))";
    config = std::regex_replace(config, expr, "$1", std::regex_constants::format_no_copy);
    return config == "" ? defval : config;
}

      

FULL CODE (using std :: stoi and std :: stof to convert the string to a number when needed, and use the automatic type because the right-hand side (RHS) lets you know what the type is):

#include "stdafx.h"
#include <string>
#include <regex>
#include <iostream>

std::string Config_GetValue(std::string key, std::string config, std::string defval)
{
    std::regex expr;
    match = key+"\\s*=\\s*((?:[\\d.]+)|(?:\".*\"))";
    config = std::regex_replace(config, expr, "$1", std::regex_constants::format_no_copy);
    return config == "" ? defval : config;
}


int main()
{
    //test string
    std::string s = "    ### MODULES ###\nTuner         =  \n PitchDetector = 1\n PhaseLocker = 0 \nFileOutput    = 1\n\n### FILE MANAGER ###\nRenameFile_AvgFreq  =  dfgsdfg dsf gdfs g #gdrgk\nRenameFile_NoteName = 0\n    RenameFile_Prefix   = \"The String Is Good\"\nRenameFile_Suffix   = \"\"\nOutputFolder        = \"..\\Folder\\String\\\"\n\n### PITCH DETECTOR ###\nAnalysisChannel = 1  #int starting from 1\nBlockSize             = 1024  #power of 2\nOverlap               = 16 #power of 2\nNormalizeForDetection = 0\n\n### TUNER ###\nSmoothing = 0.68\nEnvelope  = 0.45\n\n### PHASELOCKER ###\nFFTSize    = 1024 #powert of 2\nFFTOverlap = 54687\nWindowType = 0\nMaxFreq    = 5000";

    //Modules   
    auto FileOutput    = stoi(Config_GetValue("FileOutput", s, "0"));
    auto PitchDetector = stoi(Config_GetValue("PitchDetector", s, "0"));
    auto Tuner         = stoi(Config_GetValue("Tuner", s, "0"));
    auto PhaseLocker   = stoi(Config_GetValue("PhaseLocker", s, "0"));

    //File Manager
    auto RenameFile_AvgFreq  = stoi(Config_GetValue("RenameFile_AvgFreq", s, "0"));
    auto RenameFile_NoteName = stoi(Config_GetValue("RenameFile_NoteName", s, "0"));
    auto RenameFile_Prefix   = Config_GetValue("RenameFile_Prefix", s, "");
    auto RenameFile_Suffix   = Config_GetValue("RenameFile_Suffix", s, "");
    auto OutputFolder        = Config_GetValue("FileOutput", s, "");

    //Pitch Detector
    auto AnalysisChannel       = stoi(Config_GetValue("AnalysisChannel", s, "1"));
    auto BlockSize             = stoi(Config_GetValue("BlockSize", s, "4096"));
    auto Overlap               = stoi(Config_GetValue("Overlap", s, "8"));
    auto NormalizeForDetection = stoi(Config_GetValue("NormalizeForDetection", s, "0"));

    //Tuner 
    auto Smoothing     = stof(Config_GetValue("Smoothing", s, ".5"));
    auto Envelope      = stof(Config_GetValue("Envelope", s, ".3"));
    auto TransientTime = stof(Config_GetValue("TransientTime", s, "0"));

    //Phaselocker   
    auto FFTSize       = stoi(Config_GetValue("FFTSize", s, "1"));
    auto FFTOverlap    = stoi(Config_GetValue("FFTOverlap", s, "1"));
    auto FFTWindowType = stoi(Config_GetValue("FFTWindowType", s, "1"));
    auto FFTMaxFreq    = stof(Config_GetValue("FFTMaxFreq", s, "0.0"));

    std::cout << "complete";
    return 0;
}

      

+2


source







All Articles