检测 2 个字符串中第一个差异的位置

Posted

技术标签:

【中文标题】检测 2 个字符串中第一个差异的位置【英文标题】:Detect position of first difference in 2 strings 【发布时间】:2015-12-27 19:10:00 【问题描述】:

javascript 中查找任意两个字符串的第一个差异位置的最简洁方法是什么?

var a = 'in the';
var b = 'in he';
findFirstDiffPos(a, b); // 3

var c = 'in the beginning';
findFirstDiffPos(a, c); // 6 

【问题讨论】:

c.indexOf(a) else a foreach 遍历每个字符 【参考方案1】:

您可以简单地遍历您的字符串并逐个字符地检查它。

document.body.innerhtml += findFirstDiffPos("in he", "in the") + "<br/>";
document.body.innerHTML += findFirstDiffPos("abcd", "abcde") + "<br/>";
document.body.innerHTML += findFirstDiffPos("zxc", "zxc");

function findFirstDiffPos(a, b)

   var shorterLength = Math.min(a.length, b.length);

   for (var i = 0; i < shorterLength; i++)
   
       if (a[i] !== b[i]) return i;
   

   if (a.length !== b.length) return shorterLength;

   return -1;

输出为 3 4 -13:因为字符串在位置 3 处不同4 : string abcdabcde 的前缀,但它们的长度不同。第 4 个 (基于 0) 字符在字符串 abcd 中不存在。您可以根据自己的要求更改此逻辑-1:字符串相等

更新:正如@torazaburo 在 cmets 中提到的那样,代码可以更简单 - 只需循环直到其长度的Math.max()。它会起作用,因为i &gt;= s.lengths[i] 将返回undefined 并且条件将导致true

document.body.innerHTML += findFirstDiffPos("in he", "in the") + "<br/>";
document.body.innerHTML += findFirstDiffPos("abcd", "abcde") + "<br/>";
document.body.innerHTML += findFirstDiffPos("zxc", "zxc");

function findFirstDiffPos(a, b)

  var longerLength = Math.max(a.length, b.length);
  for (var i = 0; i < longerLength; i++)
  
     if (a[i] !== b[i]) return i;
  

  return -1;

【讨论】:

最后两行可以是return a.length != b.length? shorterLength : -1; 您可以使用longerLength 而不是shorterLength 来加强这一点。然后可以省略倒数第二行。 @torazaburo 我试图提供合乎逻辑且易于理解的示例。但是,您的方法听起来很轻松,我会将其添加到我的答案中。【参考方案2】:

该函数可以使用一些 ES5 特性:

function firstDiff(a, b) 
  var idx;

  // Short ciruit if strings are the same
  if (a == b) return -1;

  // Go until difference found
  a.split('').every(function (c, i) 
    idx = i;
    return c == b[i]; 
  );
  return idx;

这将在最短字符串的末尾自动返回。

编辑

一些代码高尔夫会导致以下内容:

// Concise for loop
function firstDiff(a, b) 
  for (var i=0; i<a.length; i++)
    if (a[i] != b[i]) return i;
  return i<b.length? i : -1;

或使用 ECMAScript 2015 findIndex

function firstDiff(a, b) 
  var i = a.split('').findIndex(function(c, i) return c != b[i]);
  return a == b? -1 : i == -1? a.length : i;

但也许可读性会受到影响。选择的标准是什么?

torazaburo 的 while 循环工作的 For 循环版本(使用基本方法是值得的,因为它们通常比迭代器快得多,而且代码也不多,如果有的话):

function findFirstDiffPos(a, b) 
  if (a === b) return -1;
  for (var i=0; a[i] == b[i]; i++) 
  return i;

【讨论】:

这使用了 ECMAScript 2015 的哪些功能? @torazaburo——哎呀! every 在 ES5 中出现...已修复。【参考方案3】:

循环

循环方法可以写得更简洁一些

function findFirstDiffPos(a, b) 
  var i = 0;
  if (a === b) return -1;
  while (a[i] === b[i]) i++;
  return i;

根据jsperf 的说法,这个替代方案比这里的其他方案快 5-20 倍,这不足为奇。

Array#findIndex

由于我们试图找到某个条件成立的索引,这似乎是findIndex 的完美应用:

function findFirstDiffPos(a, b) 
  if (a.length < b.length) [a, b] = [b, a];
  return [...a].findIndex((chr, i) => chr !== b[i]);

(我们需要较长的数组作为我们查找的数组,因此如有必要我们颠倒顺序。我们使用[...a] 将字符串转换为字符数组。)

免责声明:这是一个 ES6 接口,您必须在 IE(但不是 Edge)上进行 polyfill。

这种替代方案比直线循环慢了惊人的 20 倍。

递归

只是为了好玩,这里有一个递归解决方案:

function findFirstDiffPos(a, b) 
  return function _iterate([headA, ...tailA], [headB, ...tailB], n) 
    return headA !== headB ? n : headA === undefined) ? -1 : _iterate(tailA, tailB, n+1);
  (a.split(''), b.split(''), 0);

正则表达式

也在“只是为了好玩”类别中,一个正则表达式解决方案。我们将从一个字符串构造一个/^(a(b(c)?)?)?/ 形式的正则表达式,并将其与另一个字符串进行匹配,并检查匹配的长度。

function make_regexp(str) 
  var result = '';
  for (var i = str.length-1; i >= 0; i--)
    result = '(' + str[i] + result + ')?';
  return '^' + result;


function findFirstDiffPos(a, b) 
  return a === b ? -1 : b.match(make_regexp(a))[0].length;

即使我们预编译正则表达式,这仍然比普通的旧循环慢五倍。

【讨论】:

我喜欢 while 解决方案,总体上可能最快,同时保持简洁。【参考方案4】:

为了好玩,这里有一个班轮。虽然它不是特别可读

const findFirstDiffPos = (a, b) => [a, b].sort((a, b) => b.length - a.length).reduce((a, b) => [...a].findIndex((c, i) => c !== b[i]))

【讨论】:

以上是关于检测 2 个字符串中第一个差异的位置的主要内容,如果未能解决你的问题,请参考以下文章

java中怎么截取字符串中第二个小数点之前的字符,比如10.2.3,我要的字符为10.2,求各位大虾帮忙!

vb一个字符串在另一个字符串中第二次出现的位置?

单词错误纠正功能 编辑距离 最大公共字串 两个字符串的相似度 差异度

excel 查找某个字符在某行中第N次出现位置

awk 查找两个文件中第二个字段之间的差异

java:获取字符串中第一个汉字和第一个汉字汉字标点符号的位置?