-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from JustaFrank/master
Added text difference finder
- Loading branch information
Showing
4 changed files
with
157 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.deleted { | ||
background-color: rgb(255, 200, 200); | ||
} | ||
.added { | ||
background-color: rgb(200, 255, 200); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||
<title>Document</title> | ||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"> | ||
<link type="text/css" rel="stylesheet" href="css/text_difference.css"> | ||
</head> | ||
|
||
<body> | ||
<div class="container"> | ||
<h1>text difference finder</h1> | ||
<form id="textForm" method="submit"> | ||
<label for="original">Original Text</label> | ||
<input name="original" type="text"> | ||
<label for="changed">Changed Text</label> | ||
<input name="changed" type="text"> | ||
<button class="btn waves-effect waves-light" type="submit" name="action">Submit</button> | ||
</form> | ||
<p id="difference"></p> | ||
<p id="deletions"></p> | ||
<p id="additions"></p> | ||
</div> | ||
|
||
<script src="js/text_difference.js"></script> | ||
<script> | ||
let form = document.getElementById("textForm"); | ||
form.addEventListener("submit", event => { | ||
event.preventDefault(); | ||
let formData = new FormData(form); | ||
let originalText = formData.get("original"); | ||
let changedText = formData.get("changed"); | ||
let [dif, del, add] = findTextDifference(originalText, changedText); | ||
document.getElementById("difference").innerHTML = "<b>Total Difference</b><br>" + dif; | ||
document.getElementById("deletions").innerHTML = "<b>Deletions</b><br>" + del; | ||
document.getElementById("additions").innerHTML = "<b>Additions</b><br>" + add; | ||
}); | ||
</script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/** | ||
* Text difference module | ||
* Relevant functions: | ||
* @method longestCommonSubsequence - used to find common phrases between 2 pieces of text. | ||
* @method getDifferenceStrings - used to construct a string to disply in HTML highlighting differences. | ||
*/ | ||
|
||
// Returns difference strings from 2 pieces of text. | ||
function findTextDifference(originalText, changedText) { | ||
let originalWords = originalText.split(" "); | ||
let changedWords = changedText.split(" "); | ||
|
||
let commonPhrases = longestCommonSubsequence(originalWords, changedWords); | ||
|
||
return getDifferenceStrings(commonPhrases, originalWords, changedWords); | ||
} | ||
|
||
// Dynamic programming longest common subsequence algorithm. | ||
let arr = undefined; | ||
|
||
function longestCommonSubsequence(a, b) { | ||
let m = a.length; | ||
let n = b.length; | ||
arr = [...Array(m + 1)].map(e => Array(n + 1)); | ||
return lcs(a, b, m, n); | ||
} | ||
|
||
function lcs(a, b, m, n) { | ||
if (arr[m][n] != undefined) { | ||
return arr[m][n]; | ||
} | ||
|
||
let result = undefined; | ||
if (m === 0 || n === 0) { | ||
result = []; | ||
} else if (a[m - 1] === b[n - 1]) { | ||
result = lcs(a, b, m - 1, n - 1).concat(a[m - 1]); | ||
} else { | ||
let lcs1 = lcs(a, b, m - 1, n); | ||
let lcs2 = lcs(a, b, m, n - 1); | ||
result = lcs1 > lcs2 ? lcs1 : lcs2; | ||
} | ||
|
||
arr[m][n] = result; | ||
return result; | ||
} | ||
|
||
// Constructs 3 strings that highlight the differences (deletions & additions) between 2 texts. | ||
function getDifferenceStrings(commonPhrases, originalWords, changedWords) { | ||
let differenceStr = ""; | ||
let deletionsStr = ""; | ||
let additionsStr = ""; | ||
|
||
for (let i = 0; i <= commonPhrases.length; i++) { | ||
let phrase = ""; | ||
let phraseIdxO = originalWords.length; | ||
let phraseIdxC = changedWords.length; | ||
|
||
if (i !== commonPhrases.length) { | ||
phrase = commonPhrases[i]; | ||
phraseIdxO = originalWords.indexOf(phrase); | ||
phraseIdxC = changedWords.indexOf(phrase); | ||
} | ||
|
||
let deletedStr = substringFromWordlist(originalWords, 0, phraseIdxO); | ||
let addedStr = substringFromWordlist(changedWords, 0, phraseIdxC); | ||
|
||
differenceStr += ` | ||
<span class="deleted">${deletedStr}</span> | ||
<span class="added">${addedStr}</span> | ||
<span class="unchanged">${phrase}</span> | ||
`; | ||
deletionsStr += ` | ||
<span class="deleted">${deletedStr}</span> | ||
<span class="unchanged">${phrase}</span> | ||
`; | ||
additionsStr += ` | ||
<span class="added">${addedStr}</span> | ||
<span class="unchanged">${phrase}</span> | ||
`; | ||
|
||
originalWords.splice(0, phraseIdxO + 1); | ||
changedWords.splice(0, phraseIdxC + 1); | ||
} | ||
|
||
return [differenceStr, deletionsStr, additionsStr]; | ||
} | ||
|
||
function substringFromWordlist(wordlist, start, end) { | ||
if (end < start) return ""; | ||
let words = wordlist.slice(start, end); | ||
return arrToString(words); | ||
} | ||
|
||
function arrToString(arr) { | ||
str = ""; | ||
for (let i = 0; i < arr.length; i++) { | ||
str += arr[i] + " "; | ||
} | ||
return str; | ||
} |