2

If I have a string which has been mutated in two different ways, is there any way I could combine these into one, with just one function, using the original and the two mutated ones? Like an automatic merge in github?

Example input/output:

Original: "I have a boat",

Mut1: "I have boat" - deletion of "a"

Mut1: "I have a boat, cool." - add of ", cool"

-> "I have boat, cool." - both changes included

Why I want this:

I have a webapp in which multiple people can edit text and every 10 sec the software looks for an update in the database. So if someone IS editing the text (change1) and someone else has updated the text (change2), then the original text is still saved at the person who is currently editing the text. That way you know change1 and change2 is based on the original text. When the update comes (change2) to the person doing change1 I want to merge the two texts.

Ferus
  • 1,080
  • 3
  • 12
  • 17
  • Give a sample input and output! – Pranesh Ravi Oct 29 '16 at 16:17
  • I added a example. – Ferus Oct 29 '16 at 16:50
  • strings are immutable in JavaScript. You can of course reassign a new string to the variable that already had a string. But that is *not* mutation. – trincot Oct 29 '16 at 17:03
  • @trincot Yes of course, expressed myself incorrectly there. I ment I change it and then assign it to a new variable. – Ferus Oct 29 '16 at 17:14
  • @Ferus _"Yes of course, expressed myself incorrectly there. I ment I change it and then assign it to a new variable."_ What issue are you having assigning new string to a variable? – guest271314 Oct 29 '16 at 17:33
  • @guest271314 Nothing, my issue is that I wanted to "merge" two changes to a string into one final string containing both changes, sort of like github does to merge of code, but to a string of text. – Ferus Oct 29 '16 at 18:05
  • @Ferus Have you tried using `.concat()`, as described at Answer? – guest271314 Oct 29 '16 at 18:08
  • @guest271314 Ye, I don't understand what it does, but its only one input, I want 3, the original, the first change and the second change. – Ferus Oct 29 '16 at 18:16
  • @Ferus What do you mean? – guest271314 Oct 29 '16 at 18:18
  • Yes, [there are ways](https://en.wikipedia.org/wiki/Merge_(version_control)#Merge_algorithms), for example the one that `git merge` uses, but they're quite complicated. – Bergi Oct 29 '16 at 18:19
  • This question needs more clarification. In the example given it seems you assume the second "mutation" was performed based on the original version, but how do you know this? What if it was based on the first mutated version? Then the final version really should be equal to the second "mutation".... – trincot Oct 29 '16 at 18:19
  • @Bergi What is OP trying to achieve? `diff` results? – guest271314 Oct 29 '16 at 18:22
  • @guest271314 Are you familiar with `git merge`? An original revision, two commits based on it, now compute their combination. – Bergi Oct 29 '16 at 18:24
  • @trincot I have a webapp in which multiple people can edit text and every 10 sec the software looks for an update in the database. So if someone IS editing the text (change1) and someone else has updated the text (change2), then the original text is still saved at the person who is currently editing the text. That way you know change1 and change2 is based on the original text. Hope it makes sense. – Ferus Oct 29 '16 at 18:25
  • Yes, I understand, but you did not provide a complete example in that respect *in your question*. – trincot Oct 29 '16 at 18:26
  • @Bergi Yes, it's something liek git merge I'm looking for. Is there any way to find maybe a library that could help me or source code to it? – Ferus Oct 29 '16 at 18:26
  • @guest271314 No, that linked question seems to be about a diffing algorithm. OP needs more: applying two possibly conflicting diffs. This is also known as a "linearisation". – Bergi Oct 29 '16 at 18:28
  • @Bergi The two or more different mutations could be used at pattern at http://stackoverflow.com/a/31103393/ ? If, in your opinion, this is not adequate will vote to reopen the present Question. – guest271314 Oct 29 '16 at 18:33
  • @Ferus You could of course study the git source code, but that's non-trivial. I found some interesting links [here](http://darcs.net/Talks), but no libraries. – Bergi Oct 29 '16 at 18:37
  • @guest271314 OP does not want to detect mutations (edits) only, but also *combine two (conflicting) edits into one*. I've already reopened it :-) – Bergi Oct 29 '16 at 18:39
  • @Bergi Not sure how the pattern at linked Answer could not be used? The original text is stored. Each edit is stored. Not clear, here, why `"a"` is removed from result? – guest271314 Oct 29 '16 at 18:45
  • @guest271314 Because the second mutation is based on the original, not on the result of the first mutation. Now we'd have one edit removes the "a" and another one that adds ", cool", and we want to combine them into one that does both, then apply that to the original. – Bergi Oct 29 '16 at 18:50
  • @Bergi Yes, each edit can be stored, then return concatenated or reduced result based on which edits user selects, or all edits using index of character in string. – guest271314 Oct 29 '16 at 19:07
  • 1
    @guest271314 No selection necessary, the user will want both. And just using indices is not enough, as applying one edit already changes the indices. You might want to post an answer that shows how this would work. – Bergi Oct 29 '16 at 19:12
  • [Rope](https://en.wikipedia.org/wiki/Rope_%28data_structure%29)? – GingerPlusPlus Oct 30 '16 at 16:34

1 Answers1

0

Use String.prototype.match() with RegExp /[a-z,.!?;]+/ig to create arrays of original and subsequent mutations of original string, matching letters, words and punctuation marks. Iterate Array.prototype.entries() of array of last mutation of original string returned by .match() to utilize index of element of source array as to original array which .entries() returns at for..of loop. Within for..of loop use logic to check if current letter or word index is 1) equal to word at index of original string including punctuation marks; or equal to word at index of original string without punctuation marks; 2) and equal to previous mutation of original string at current index; 3) previous mutation of original string at current index is undefined; or 4) current index is not equal to original index or current index; that is, has new content. Push the matches to an array, use Array.prototype.join() with parameter " " to form the mutated string based on original string, and previous and current mutations of original string.

const mergediffs = (...mutations) => {
  let [original, mut1, mut2, result] = [...mutations, []];
  // additional punctuation marks can be added to RegEx
  let [rgx, marks, re] = [/[a-z,.!?;]+/ig, /[,.!?]/g, ""];
  let [odata, m1data, m2data] = [original.match(rgx)
                                 , mut1.match(rgx)
                                 , mut2.match(rgx)];

  for (let currentMut of m2data.entries()) {
    let [index, curr] = currentMut;
    if (((curr === odata[index] 
         || curr.replace(marks, re) === odata[index])
         && curr.replace(marks, re) === m1data[index])
        || (m1data[index] === undefined 
            || curr !== odata[index] 
            && curr !== m1data[index] 
               || curr === m1data[index])) {
      result = [...result, curr]
    }
  }
  return result.join(" ")
}

let pre = document.querySelector("pre");
pre.textContent = mergediffs(
  "I have a boat"
  , "I have boat"
  , "I have a boat, cool"
);

pre.textContent += "\n" + mergediffs(
  "I have a boat"
  , "We have a monkey"
  , "We had a monkey, cool."
);
<pre></pre>
guest271314
  • 1
  • 15
  • 104
  • 177
  • Doesnt seem to work on for example: Org: "I have a boat", mut1: "I have a monkey", mut2: "I had a monkey, cool" in which "a cool" is returned. – Ferus Oct 30 '16 at 17:06
  • @Ferus `"cool"` is returned at original example as well when included as part of a mutation. What is expected result for the sequence; and logic which determines the sequence for expected result? – guest271314 Oct 30 '16 at 17:09
  • What do you mean? The example I specified in the question seem to work with your code. But if I take the example in which "I have a boat" is the original, mutation 1 is "We have a monkey" and mutation 2 is "I had a boat, cool", then the expected result is "We had a monkey, cool" but your code return "a cool" – Ferus Oct 30 '16 at 17:22
  • Why is `"boat"` not in expected return value? Is `"a"` at `"a cool"` the only letter that should not be included in result? – guest271314 Oct 30 '16 at 17:26
  • Mutation 1 changes "I" -> "We", "Boat" -> "Monkey", second mutation changes "Have" -> "Had" and in the end adds ", cool". – Ferus Oct 30 '16 at 17:29
  • @Ferus See updated post. The basic approach is to utilize conditions to evaluate the input for the possible outcomes given the input set. – guest271314 Oct 30 '16 at 20:00
  • @Ferus Given three inputs and a finite number of words for each input, there is a finite number of possible outcomes. At second glance the process resembles boolean algebra. – guest271314 Oct 30 '16 at 20:10
  • If you change last mutation from "We had a monkey, cool" to "I had a boat, cool" then it will return "had a boat, cool" and not "We had a monkey, cool", so it doesn't seem to work in all cases. – Ferus Oct 30 '16 at 20:54
  • I'm working on a solution aswell where Im trying to utilize jsdiff, haven't gotten it to work as of yet. Seems neat to use regex though. – Ferus Oct 30 '16 at 20:58
  • @Ferus Should not "had a boat" be included when changed back to portions of original input at last mutation? _"If you change last mutation from "We had a monkey, cool" to "I had a boat, cool""_ That would be similar to first example, yes? – guest271314 Oct 30 '16 at 21:00
  • Last mutation isn't last its at the same time as the second mutation. Because its the same "had a boat" it means that part of the text haven't been touched. So if it hasn't been touched and the first mutation changes it, it should be changed. As an example: if the text is "I had a boat" and person 1 wants to change some spelling errors and person 2 wants to continue working on the text. Person 1 changes "had" to "have" and person to adds ", cool" then "had" should be "have" in the final-mutation. – Ferus Oct 30 '16 at 21:02
  • Not sure follow. You mentioned changing last mutation. What are original and two mutations? Can you include what you have tried at Question? – guest271314 Oct 30 '16 at 21:04
  • Basically according to the computer the only thing the second mutation has done is changed "have" to "had" and added ", cool" Thats all he has done. He hasnt touched anything else. While the other person actually touch "a boat" and changed it to "a monkey" – Ferus Oct 30 '16 at 21:07
  • Added what Im trying to do. Just in progress so not too beautiful. – Ferus Oct 30 '16 at 21:11