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

meteor - inserting data to database gives error "insert failed: Method '/texts/insert' not found" -

angular - DownloadURL return null in below code -