查找两个string之间不同的第一个字符

给定两个等长的string,是否有一个优雅的方式来获得第一个不同的字符的偏移量?

显而易见的解决scheme是:

for ($offset = 0; $offset < $length; ++$offset) { if ($str1[$offset] !== $str2[$offset]) { return $offset; } } 

但是这看起来不太正确,这是一个简单的任务。

您可以使用按位XOR( ^ )的一个很好的属性来实现此目的:基本上,当您将两个string异或时,相同的字符将变为空字节( "\0" )。 所以,如果我们使用这两个string,我们只需要使用strspn来查找第一个非空字节的位置:

 $position = strspn($string1 ^ $string2, "\0"); 

这里的所有都是它的。 我们来看一个例子:

 $string1 = 'foobarbaz'; $string2 = 'foobarbiz'; $pos = strspn($string1 ^ $string2, "\0"); printf( 'First difference at position %d: "%s" vs "%s"', $pos, $string1[$pos], $string2[$pos] ); 

这将输出:

第7位的第一个区别是:“a”与“i”

所以应该这样做。 这是非常有效的,因为它只使用C函数,并且只需要string的单个内存副本。

编辑:同一行的MultiByte解决scheme:

 function getCharacterOffsetOfDifference($str1, $str2, $encoding = 'UTF-8') { return mb_strlen( mb_strcut( $str1, 0, strspn($str1 ^ $str2, "\0"), $encoding ), $encoding ); } 

首先使用上述方法find字节级别的差异,然后将偏移量映射到字符级别。 这是使用mb_strcut函数完成的,该函数基本上是substr但是却遵守多字节字符边界。

 var_dump(getCharacterOffsetOfDifference('foo', 'foa')); // 2 var_dump(getCharacterOffsetOfDifference('©oo', 'foa')); // 0 var_dump(getCharacterOffsetOfDifference('f©o', 'fªa')); // 1 

它不像第一个解决scheme那么优雅,但它仍然是一个单行(如果您使用默认编码更简单一点):

 return mb_strlen(mb_strcut($str1, 0, strspn($str1 ^ $str2, "\0"))); 

如果将string转换为单字符数组的一个字节值,则可以使用数组比较函数来比较string。

您可以使用以下方法获得与XOR方法类似的结果。

 $string1 = 'foobarbaz'; $string2 = 'foobarbiz'; $array1 = str_split($string1); $array2 = str_split($string2); $result = array_diff_assoc($array1, $array2); $num_diff = count($result); $first_diff = key($result); echo "There are " . $num_diff . " differences between the two strings. <br />"; echo "The first difference between the strings is at position " . $first_diff . ". (Zero Index) '$string1[$first_diff]' vs '$string2[$first_diff]'."; 

编辑:多字节解决scheme

 $string1 = 'foorbarbaz'; $string2 = 'foobarbiz'; $array1 = preg_split('((.))u', $string1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); $array2 = preg_split('((.))u', $string2, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); $result = array_diff_assoc($array1, $array2); $num_diff = count($result); $first_diff = key($result); echo "There are " . $num_diff . " differences between the two strings.\n"; echo "The first difference between the strings is at position " . $first_diff . ". (Zero Index) '$string1[$first_diff]' vs '$string2[$first_diff]'.\n"; 

我想添加这个作为评论的最佳答案,但我没有足够的分数。

 $string1 = 'foobarbaz'; $string2 = 'foobarbiz'; $pos = strspn($string1 ^ $string2, "\0"); if ($pos < min(strlen($string1), strlen($string2)){ printf( 'First difference at position %d: "%s" vs "%s"', $pos, $string1[$pos], $string2[$pos] ); } else if ($pos < strlen($string1)) { print 'String1 continues with' . substr($string1, $pos); } else if ($pos < strlen($string2)) { print 'String2 continues with' . substr($string2, $pos); } else { print 'String1 and String2 are equal'; } 
 string strpbrk ( string $haystack , string $char_list ) 

strpbrk()在haystackstring中search一个char_list。

返回值是$ haystack的子string,从第一个匹配的字符开始。 作为一个API函数,它应该是zippy。 然后循环一次,查找返回的string的偏移量零以获得您的偏移量。