C++ - Get the "difference" of 2 strings like git -


i'm working on project includes win32 console program on windows 10 pc , app windows 10 mobile phone. it's controlling master , audio session volumes on pc on app on windows phone.

the "little" problem have right "difference" between 2 strings.

let's take these 2 strings example:

std::string oldvolumes = "master:50:system:50:steam:100:uplay:100"; std::string newvolumes = "master:30:system:50:steam:100:rocketleague:80:chrome:100"; 

now want compare these 2 strings. lets explode each string vector ":" delimiter (i have function named explode cut given string delimiter , write string before vector).

good enough. can see, in old string there's uplay value 100, it's missing in new string. also, there 2 new values (rocketleague , chrome), missing in old one. not "audio sessions/names" different, values different too.

what want each session, in both strings (like master , system), compare values , if the new value different old one, want append change string, like:

std::string volumechanges = "master:30"; // cause master changed, system not 

if there's session in old string, not in new one, want append:

std::string volumechanges = "master:30:remove:uplay"; 

if there's session in new one, missing in old string, want append that:

std::string volumechanges = "master:30:remove:uplay:add:rocketleague:rocketleague:80:add:chrome:chrome:100"; 

the volumechanges string show you, need. i'll try make better 1 afterwards.

do have ideas of how implement such comparison? don't need specific code example or something, ideas of how in theory. it's git @ least. if make changes in text file, see in red deleted text , in green added one. similar this, strings or vectors of strings.

lets explode each string vector ":" delimiter (i have function named explode cut given string delimiter , write string before vector).

i'm going advise further extend logic separate them property objects discretely maintain name + value:

struct property {     std::string name;     in32_t value;      bool same_name(property const& o) const {         return name == o.name;     }      bool same_value(property const& o) const {         return value == o.value;     }      bool operator==(property const& o) const {         return same_name(o) && same_value(o);     }      bool operator<(property const& o) const {         if(!same_name(o)) return name < o.name;         else return value < o.value;     } }; 

this dramatically simplify logic needed work out properties changed/added/removed.

the logic "tokenizing" kind of string isn't difficult:

std::set<property> tokenify(std::string input) {     bool finding_name = true;     property prop;     std::set<property> properties;     while (input.size() > 0) {         auto colon_index = input.find(':');         if (finding_name) {             prop.name = input.substr(0, colon_index);             finding_name = false;         }         else {             prop.value = std::stoi(input.substr(0, colon_index));             finding_name = true;             properties.insert(prop);         }         if(colon_index == std::string::npos)              break;         else              input = input.substr(colon_index + 1);     }     return properties; } 

then, function difference:

std::string get_diff_string(std::string const& old_props, std::string const& new_props) {     std::set<property> old_properties = tokenify(old_props);     std::set<property> new_properties = tokenify(new_props);      std::string output;      //we first scan properties either removed or changed     (property const& old_property : old_properties) {         auto predicate = [&](property const& p) {             return old_property.same_name(p);         };         auto = std::find_if(new_properties.begin(), new_properties.end(), predicate);         if (it == new_properties.end()) {             //we didn't find property, need indicate removed             output.append("remove:" + old_property.name + ':');         }         else if (!it->same_value(old_property)) {             //found property, value changed.             output.append(it->name + ':' + std::to_string(it->value) + ':');         }     }      //finally, need see added.     (property const& new_property : new_properties) {         auto predicate = [&](property const& p) {             return new_property.same_name(p);         };         auto = std::find_if(old_properties.begin(), old_properties.end(), predicate);         if (it == old_properties.end()) {             //we didn't find property, need indicate added             output.append("add:" + new_property.name + ':' + new_property.name + ':' + std::to_string(new_property.value) + ':');         }         //the previous loop detects changes, don't need bother here.     }      if (output.size() > 0)         output = output.substr(0, output.size() - 1); //trim off last colon      return output; } 

and can demonstrate it's working simple main function:

int main() {     std::string diff_string = get_diff_string("master:50:system:50:steam:100:uplay:100", "master:30:system:50:steam:100:rocketleague:80:chrome:100");     std::cout << "diff string \"" << diff_string << '\"' << std::endl; } 

which yields output (according ideone.com):

diff string "master:30:remove:uplay:add:chrome:chrome:100:add:rocketleague:rocketleague:80" 

which, although contents in different order example, still contains correct information. contents in different order because std::set implicitly sorted attributes name when tokenizing properties; if want disable sorting, you'd need use different data structure preserves entry order. chose because eliminates duplicates, cause odd behavior otherwise.


Comments

Popular posts from this blog

What is happening when Matlab is starting a "parallel pool"? -

angular - DownloadURL return null in below code -

php - Cannot override Laravel Spark authentication with own implementation -