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
Post a Comment