【问题标题】:Find difference between two strings in JavaScript在 JavaScript 中查找两个字符串之间的差异
【发布时间】:2019-07-18 20:53:58
【问题描述】:

我需要找出两个字符串之间的差异。

const string1 = 'lebronjames';
const string2 = 'lebronnjames';

预期的输出是找到多余的n 并将其记录到控制台。

有没有办法在 JavaScript 中做到这一点?

【问题讨论】:

  • 还有b吗?
  • 你能澄清你期望的输出吗?你只是想找到第一个不同的角色吗?或者,您是否需要找到所有不同的字符?如果是全部,您对第一个之后的字符使用什么样的阈值?
  • 它应该双向工作并显示缺失的字符吗?
  • 你应该考虑计算编辑距离:en.wikipedia.org/wiki/Edit_distance
  • 这是一个比您想象的要复杂得多的操作。您的算法如何知道应该比较第一个 n 之后的任何子字符串?从严格的字母:字母的角度来看,字符串的整个后半部分是不同的。

标签: javascript string algorithm difference


【解决方案1】:

对于更复杂的差异检查,另一种选择是使用 PatienceDiff 算法。我将此算法移植到 Javascript 在...

https://github.com/jonTrent/PatienceDiff

...虽然该算法通常用于逐行比较文本(例如计算机程序),但它仍然可以用于逐字符比较。例如,要比较两个字符串,您可以执行以下操作...

let a = "thelebronnjamist";
let b = "the lebron james";

let difference = patienceDiff( a.split(""), b.split("") );

...difference.lines 被设置为具有比较结果的数组...

difference.lines: Array(19)

0: {line: "t", aIndex: 0, bIndex: 0}
1: {line: "h", aIndex: 1, bIndex: 1}
2: {line: "e", aIndex: 2, bIndex: 2}
3: {line: " ", aIndex: -1, bIndex: 3}
4: {line: "l", aIndex: 3, bIndex: 4}
5: {line: "e", aIndex: 4, bIndex: 5}
6: {line: "b", aIndex: 5, bIndex: 6}
7: {line: "r", aIndex: 6, bIndex: 7}
8: {line: "o", aIndex: 7, bIndex: 8}
9: {line: "n", aIndex: 8, bIndex: 9}
10: {line: "n", aIndex: 9, bIndex: -1}
11: {line: " ", aIndex: -1, bIndex: 10}
12: {line: "j", aIndex: 10, bIndex: 11}
13: {line: "a", aIndex: 11, bIndex: 12}
14: {line: "m", aIndex: 12, bIndex: 13}
15: {line: "i", aIndex: 13, bIndex: -1}
16: {line: "e", aIndex: -1, bIndex: 14}
17: {line: "s", aIndex: 14, bIndex: 15}
18: {line: "t", aIndex: 15, bIndex: -1}

aIndex === -1bIndex === -1 表示两个字符串之间的差异。具体...

  • 元素 3 表示在位置 3 的 b 中找到字符“”。
  • 元素 10 表示在位置 9 的 a 中找到了字符“n”。
  • 元素 11 表示在位置 10 的 b 中找到字符“”。
  • 元素 15 表示在 a 的位置 13 中找到了字符“i”。
  • 元素 16 表示在位置 14 的 b 中找到了字符“e”。
  • 元素 18 表示在位置 15 的 a 中找到字符“t”。

请注意,PatienceDiff 算法对于比较两个相似的文本或字符串块很有用。它不会告诉您是否发生了基本编辑。比如下面...

let a = "james lebron";
let b = "lebron james";

let difference = patienceDiff( a.split(""), b.split("") );

...返回 difference.lines 包含...

difference.lines: Array(18)

0: {line: "j", aIndex: 0, bIndex: -1}
1: {line: "a", aIndex: 1, bIndex: -1}
2: {line: "m", aIndex: 2, bIndex: -1}
3: {line: "e", aIndex: 3, bIndex: -1}
4: {line: "s", aIndex: 4, bIndex: -1}
5: {line: " ", aIndex: 5, bIndex: -1}
6: {line: "l", aIndex: 6, bIndex: 0}
7: {line: "e", aIndex: 7, bIndex: 1}
8: {line: "b", aIndex: 8, bIndex: 2}
9: {line: "r", aIndex: 9, bIndex: 3}
10: {line: "o", aIndex: 10, bIndex: 4}
11: {line: "n", aIndex: 11, bIndex: 5}
12: {line: " ", aIndex: -1, bIndex: 6}
13: {line: "j", aIndex: -1, bIndex: 7}
14: {line: "a", aIndex: -1, bIndex: 8}
15: {line: "m", aIndex: -1, bIndex: 9}
16: {line: "e", aIndex: -1, bIndex: 10}
17: {line: "s", aIndex: -1, bIndex: 11}

请注意,PatienceDiff 不报告名字和姓氏的交换,而是提供一个结果,显示从a 中删除了哪些字符,以及向b 添加了哪些字符,最终结果为b.

编辑:添加了名为 patienceDiffPlus 的新算法。

在仔细考虑了上面提供的最后一个示例之后,该示例显示了 PatienceDiff 在识别可能移动的线条方面的局限性,我突然意识到有一种优雅的方法可以使用 PatienceDiff 算法来确定是否有任何线条确实可能移动了而不是不仅仅是显示删除和添加。

简而言之,我在 PatienceDiff.js 文件的底部添加了 patienceDiffPlus 算法(到上面确定的 GitHub 存储库)。 patienceDiffPlus 算法从初始 patienceDiff 算法中获取删除的 aLines[] 和添加的 bLines[],并再次通过 patienceDiff 算法运行它们。即,patienceDiffPlus 正在寻找可能移动的行的最长公共子序列,因此它将其记录在原始的patienceDiff 结果中。 patienceDiffPlus 算法会继续这个过程,直到找不到更多移动的行。

现在,使用patienceDiffPlus,下面的比较...

let a = "james lebron";
let b = "lebron james";

let difference = patienceDiffPlus( a.split(""), b.split("") );

...返回 difference.lines 包含...

difference.lines: Array(18)

0: {line: "j", aIndex: 0, bIndex: -1, moved: true}
1: {line: "a", aIndex: 1, bIndex: -1, moved: true}
2: {line: "m", aIndex: 2, bIndex: -1, moved: true}
3: {line: "e", aIndex: 3, bIndex: -1, moved: true}
4: {line: "s", aIndex: 4, bIndex: -1, moved: true}
5: {line: " ", aIndex: 5, bIndex: -1, moved: true}
6: {line: "l", aIndex: 6, bIndex: 0}
7: {line: "e", aIndex: 7, bIndex: 1}
8: {line: "b", aIndex: 8, bIndex: 2}
9: {line: "r", aIndex: 9, bIndex: 3}
10: {line: "o", aIndex: 10, bIndex: 4}
11: {line: "n", aIndex: 11, bIndex: 5}
12: {line: " ", aIndex: 5, bIndex: 6, moved: true}
13: {line: "j", aIndex: 0, bIndex: 7, moved: true}
14: {line: "a", aIndex: 1, bIndex: 8, moved: true}
15: {line: "m", aIndex: 2, bIndex: 9, moved: true}
16: {line: "e", aIndex: 3, bIndex: 10, moved: true}
17: {line: "s", aIndex: 4, bIndex: 11, moved: true}

注意添加了moved 属性,该属性标识一行(或本例中的字符)是否可能被移动。同样,patienceDiffPlus 只是匹配已删除的 aLines[] 并添加了 bLines[],因此无法保证这些行确实被移动了,但很有可能它们确实被移动了。

【讨论】:

  • 太棒了,感谢您与使用分享这个,这真的解决了一个问题!
  • 我突然意识到有一种优雅的方法可以使用patienceDiff 算法来识别可能移动的行/字符,而不是简单地识别删除和添加。我使用新的 patienceDiffPlus 算法对我的原始答案进行了编辑,并更新了我的 GitHub 存储库。
【解决方案2】:

这将返回两个字符串之间的第一个差异

喜欢lebronjameslebronnjames 的是n

const string1 = 'lebronjames';
const string2 = 'lebronnjabes';


const findFirstDiff = (str1, str2) =>
  str2[[...str1].findIndex((el, index) => el !== str2[index])];


// equivalent of 

const findFirstDiff2 = function(str1, str2) {
  return str2[[...str1].findIndex(function(el, index) {
    return el !== str2[index]
  })];
}



console.log(findFirstDiff2(string1, string2));
console.log(findFirstDiff(string1, string2));

【讨论】:

  • 虽然它没有找到它找到第一个的所有差异,但我能够用更多的代码到达那部分:D 你能向我们解释你的代码(对于新手)吗?
  • 不,你不是,我只是用findIndex 找到两个单词之间的第一个区别,然后我使用索引字符串[index],esc6 语法看起来更短
  • 感谢您的宝贵时间!我在循环认为 string1 和 string2 中的每个字符 => 比较它。那是有效的,我希望我能找到不同字符的整个序列,但我现在找到了更好的方法并学习了一点传播运算符。谢谢!
【解决方案3】:

    function getDifference(a, b)
    {
        var i = 0;
        var j = 0;
        var result = "";

        while (j < b.length)
        {
         if (a[i] != b[j] || i == a.length)
             result += b[j];
         else
             i++;
         j++;
        }
        return result;
    }
    console.log(getDifference("lebronjames", "lebronnjames"));

【讨论】:

  • 复制/粘贴上一个主题的答案,但这不起作用老兄.. :'(
【解决方案4】:

对于那些想要返回两个字符串之间的first差异的人可以这样调整:

排序和查找

const getDifference = (s, t) => {
  s = [...s].sort();
  t = [...t].sort();
  return t.find((char, i) => char !== s[i]);
};

console.log(getDifference('lebronjames', 'lebronnjames'));
console.log(getDifference('abc', 'abcd'));

添加字符代码

const getDifference = (s, t) => {
  let sum = t.charCodeAt(t.length - 1);
  for (let j = 0; j < s.length; j++) {
    sum -= s.charCodeAt(j);
    sum += t.charCodeAt(j);
  }
  return String.fromCharCode(sum);
};

console.log(getDifference('lebronjames', 'lebronnjames'));
console.log(getDifference('abc', 'abcd'));

【讨论】:

    【解决方案5】:
    function findDifference(s, t) {
    
      if(s === '') return t;
    
      
      
      // this is useless and can be omitted.
      for(let i = 0; i < t.length; i++) {
        if(!s.split('').includes(t[i])) {
          return t[i];
        }
      }
      // this is useless and can be omitted.
    
    
      
      // (if the additional letter exists)
      // cache them, count values, different values of the same letter would give the answer.
    
      const obj_S = {};
      const obj_T = {};
    
      for(let i = 0; i < s.length; i++) {
        if(!obj_S[s[i]]) {
          obj_S[s[i]] = 1;
        }else {
          obj_S[s[i]]++;
        }
      }
      
      for(let i = 0; i < t.length; i++) {
        if(!obj_T[t[i]]) {
          obj_T[t[i]] = 1;
        }else {
          obj_T[t[i]]++;
        }
      }
    
      for(const key in obj_T) {
        if(obj_T[key] !== obj_S[key]) {
          return key
        }
      }
    
    }
    
    // if more than 1 letter -> store the values and the return, logic stays the same.
    
    console.log(findDifference('john', 'johny')) // --> y
    console.log(findDifference('bbcc', 'bbbcc')) //--> b
    

    实际上第一部分可以省略(第一个 for 循环)我对边缘情况的解决方案解决了整个问题,因为如果该值不存在,它将是未定义的并且 count !== undefined 将返回字母...

    【讨论】:

      【解决方案6】:
          var findTheDifference = function(s, t) {
          let res=[...s].sort();
          let res1=[...t].sort();
          let j=0;
          while(j<res1.length){
              if(res[j]!=res1[j]){
                  return res1[j];
              }
              j++;
          }
      };
      
      console.log(findTheDifference("a","aa")) // output: a
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-08
        • 1970-01-01
        • 1970-01-01
        • 2021-01-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多