Development Tip

두 문자열에서 다른 첫 번째 문자 찾기

yourdevel 2020. 11. 6. 20:43
반응형

두 문자열에서 다른 첫 번째 문자 찾기


두 개의 동일한 길이 문자열이 주어지면 첫 번째 다른 문자의 오프셋을 얻는 우아한 방법이 있습니까?

분명한 해결책은 다음과 같습니다.

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

하지만 그렇게 간단한 작업으로는 옳지 않은 것 같습니다.


이를 위해 비트 별 XOR ( ^) 의 nice 속성을 사용할 수 있습니다 . 기본적으로 두 문자열을 함께 xor하면 동일한 문자가 널 바이트 ( "\0")가됩니다. 따라서 두 문자열을 xor하면 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의 기능을 사용하고 있기 때문에, 효율적이고, 문자열의 메모리의 단 하나의 사본이 필요합니다.

편집 : 동일한 라인에 따른 멀티 바이트 솔루션 :

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

먼저 위의 방법을 사용하여 바이트 수준의 차이를 찾은 다음 오프셋을 문자 수준에 매핑합니다. 이것은 mb_strcut기본적으로 substr멀티 바이트 문자 경계를 준수 하는 함수를 사용하여 수행됩니다 .

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

첫 번째 솔루션만큼 우아하지는 않지만 여전히 한 줄입니다 (기본 인코딩을 사용하는 경우 조금 더 간단합니다).

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

문자열을 단일 문자 1 바이트 값의 배열로 변환하는 경우 배열 비교 함수를 사용하여 문자열을 비교할 수 있습니다.

다음을 사용하여 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]'.";

편집 : 멀티 바이트 솔루션

$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";

I wanted to add this as as comment to the best answer, but I do not have enough points.

$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() searches the haystack string for a char_list.

The return value is the substring of $haystack which begins at the first matched character. As an API function it should be zippy. Then loop through once, looking for offset zero of the returned string to obtain your offset.

참고URL : https://stackoverflow.com/questions/7475437/find-first-character-that-is-different-between-two-strings

반응형