PHP에서 두 문자열의 차이를 강조 표시합니다.
PHP에서 두 문자열의 차이를 강조하는 가장 쉬운 방법은 무엇입니까?
Stack Overflow 편집 이력 페이지의 새로운 텍스트는 녹색으로, 삭제된 텍스트는 빨간색으로 되어 있습니다.미리 작성된 함수나 클래스가 있다면 이상적입니다.
한 문자열을 다른 문자열로 변환하기 위해 최소 편집 횟수(문자 그대로 사용할 수 없음)를 계산하는 클래스를 작성했습니다.
http://www.raymondhill.net/finediff/
diff의 HTML 버전을 렌더링하는 정적 함수를 가지고 있습니다.
첫 번째 버전으로 개선될 것 같습니다만, 현시점에서는 정상적으로 동작하고 있기 때문에, 누군가 필요에 따라서 콤팩트 diff를 효율적으로 생성해야 할 경우에 대비해 버립니다.
편집: 현재 Github에 있습니다.https://github.com/gorhill/PHP-FineDiff
PHP Horde_Text_Diff 패키지를 사용할 수 있었습니다.
그러나 이 패키지는 더 이상 사용할 수 없습니다.
이것은 좋은 것입니다.http://paulbutler.org/archives/a-simple-diff-algorithm-in-php/도 마찬가지입니다.
그 문제를 해결하는 것은 보기만큼 간단하지 않고, 내가 그것을 알기 전까지 약 1년 동안 그 문제가 나를 괴롭혔다.18줄의 코드로 PHP로 알고리즘을 작성했습니다.이 방법이 가장 효율적인 방법은 아니지만 가장 이해하기 쉬운 방법이 될 수 있습니다.
두 문자열에 공통되는 가장 긴 단어의 시퀀스를 찾아 하위 문자열에 공통 단어가 없을 때까지 문자열의 나머지 가장 긴 시퀀스를 재귀적으로 찾는 방식으로 작동합니다.이 시점에서 나머지 새 단어는 삽입으로, 나머지 오래된 단어는 삭제로 추가됩니다.
PHP SimpleDiff에서 소스를 다운로드할 수 있습니다.
견고한 라이브러리를 원한다면 Text_Diff(PEAR 패키지)가 좋습니다.그것은 꽤 멋진 특징들을 가지고 있다.
여기에서는, 2개의 어레이를 구별하기 위해서 사용할 수 있는 간단한 함수를 나타냅니다.LCS 알고리즘이 실장되어 있습니다.
function computeDiff($from, $to)
{
$diffValues = array();
$diffMask = array();
$dm = array();
$n1 = count($from);
$n2 = count($to);
for ($j = -1; $j < $n2; $j++) $dm[-1][$j] = 0;
for ($i = -1; $i < $n1; $i++) $dm[$i][-1] = 0;
for ($i = 0; $i < $n1; $i++)
{
for ($j = 0; $j < $n2; $j++)
{
if ($from[$i] == $to[$j])
{
$ad = $dm[$i - 1][$j - 1];
$dm[$i][$j] = $ad + 1;
}
else
{
$a1 = $dm[$i - 1][$j];
$a2 = $dm[$i][$j - 1];
$dm[$i][$j] = max($a1, $a2);
}
}
}
$i = $n1 - 1;
$j = $n2 - 1;
while (($i > -1) || ($j > -1))
{
if ($j > -1)
{
if ($dm[$i][$j - 1] == $dm[$i][$j])
{
$diffValues[] = $to[$j];
$diffMask[] = 1;
$j--;
continue;
}
}
if ($i > -1)
{
if ($dm[$i - 1][$j] == $dm[$i][$j])
{
$diffValues[] = $from[$i];
$diffMask[] = -1;
$i--;
continue;
}
}
{
$diffValues[] = $from[$i];
$diffMask[] = 0;
$i--;
$j--;
}
}
$diffValues = array_reverse($diffValues);
$diffMask = array_reverse($diffMask);
return array('values' => $diffValues, 'mask' => $diffMask);
}
2개의 어레이를 생성합니다.
- values array :diff에 표시되는 요소의 리스트.
- mask array:에는 숫자가 포함되어 있습니다.0: 변경되지 않음, -1: 삭제됨, 1: 추가됨.
배열을 문자로 채우는 경우 인라인 차이를 계산하는 데 사용할 수 있습니다.이제 차이점을 강조하기 위한 한 단계입니다.
function diffline($line1, $line2)
{
$diff = computeDiff(str_split($line1), str_split($line2));
$diffval = $diff['values'];
$diffmask = $diff['mask'];
$n = count($diffval);
$pmc = 0;
$result = '';
for ($i = 0; $i < $n; $i++)
{
$mc = $diffmask[$i];
if ($mc != $pmc)
{
switch ($pmc)
{
case -1: $result .= '</del>'; break;
case 1: $result .= '</ins>'; break;
}
switch ($mc)
{
case -1: $result .= '<del>'; break;
case 1: $result .= '<ins>'; break;
}
}
$result .= $diffval[$i];
$pmc = $mc;
}
switch ($pmc)
{
case -1: $result .= '</del>'; break;
case 1: $result .= '</ins>'; break;
}
return $result;
}
예:
echo diffline('StackOverflow', 'ServerFault')
유언 출력:
S<del>tackO</del><ins>er</ins>ver<del>f</del><ins>Fau</ins>l<del>ow</del><ins>t</ins>
StackOerverfFaulowt
기타 주의사항:
- diff 매트릭스에는 (m+1)*(n+1) 요소가 필요합니다.따라서 긴 시퀀스를 분산하려고 하면 메모리 부족 오류가 발생할 수 있습니다.이 경우 큰 청크(예: 라인)를 먼저 구별한 다음 두 번째 경로로 내용을 구별합니다.
- 처음부터 끝까지 일치하는 요소를 트리밍한 다음 다른 중간에서만 알고리즘을 실행하면 알고리즘이 개선될 수 있습니다.후자의 버전(더 비대해진 버전)에도 이러한 변경이 포함되어 있습니다.
xdiff에는 PECL 확장도 있습니다.
특히:
- xdiff_string_diff : 2개의 스트링을 통합적으로 만듭니다.
PHP 매뉴얼의 예:
<?php
$old_article = file_get_contents('./old_article.txt');
$new_article = $_POST['article'];
$diff = xdiff_string_diff($old_article, $new_article, 1);
if (is_string($diff)) {
echo "Differences between two articles:\n";
echo $diff;
}
이게 내가 찾은 것 중 최고야.
http://code.stephenmorley.org/php/diff-implementation/
PEAR 베이스의 옵션과 표시된 심플한 옵션의 양쪽 모두에 큰 문제가 있었습니다.여기 Unix diff 명령어를 활용하는 솔루션이 있습니다(유닉스 시스템에 있거나 Windows diff 명령어가 동작하고 있을 필요가 있습니다).마음에 드는 임시 디렉토리를 선택하고, 필요에 따라서 코드를 반환하도록 예외를 변경합니다.
/**
* @brief Find the difference between two strings, lines assumed to be separated by "\n|
* @param $new string The new string
* @param $old string The old string
* @return string Human-readable output as produced by the Unix diff command,
* or "No changes" if the strings are the same.
* @throws Exception
*/
public static function diff($new, $old) {
$tempdir = '/var/somewhere/tmp'; // Your favourite temporary directory
$oldfile = tempnam($tempdir,'OLD');
$newfile = tempnam($tempdir,'NEW');
if (!@file_put_contents($oldfile,$old)) {
throw new Exception('diff failed to write temporary file: ' .
print_r(error_get_last(),true));
}
if (!@file_put_contents($newfile,$new)) {
throw new Exception('diff failed to write temporary file: ' .
print_r(error_get_last(),true));
}
$answer = array();
$cmd = "diff $newfile $oldfile";
exec($cmd, $answer, $retcode);
unlink($newfile);
unlink($oldfile);
if ($retcode != 1) {
throw new Exception('diff failed with return code ' . $retcode);
}
if (empty($answer)) {
return 'No changes';
} else {
return implode("\n", $answer);
}
}
당신이 찾고 있는 것은 "diff algorithm"입니다.빠른 구글 검색을 통해 이 솔루션을 찾을 수 있었습니다.테스트하진 않았지만, 아마 당신이 원하는 대로 할 수 있을 거예요.
Neil Frasers diff_match_patch의 php 포트(Apache 2.0 라이선스)
PHP 코어에서 다음과 같은 놀라운 기능을 볼 것을 권장합니다.
silar_text : 두 문자열 간의 유사도를 계산합니다.
http://www.php.net/manual/en/function.similar-text.php
levenshtein : 2개의 문자열 사이의 Levenshtein 거리를 계산합니다.
http://www.php.net/manual/en/function.levenshtein.php
soundex : 문자열의 soundex 키를 계산합니다.
http://www.php.net/manual/en/function.soundex.php
metaphone : 문자열의 metaphone 키를 계산합니다.
http://www.php.net/manual/en/function.metaphone.php
텍스트 박스 2개와 컬러 스타일링으로 심플한 어프로치를 시도했습니다.주의: diff checker는 단어의 차이만 강조 표시하고 문자는 강조 표시하지 않습니다.
<?php
$valueOne = $_POST['value'] ?? "";
$valueTwo = $_POST['valueb'] ?? "" ;
$trimValueOne = trim($valueOne);
$trimValueTwo = trim($valueTwo);
$arrayValueOne = explode(" ",$trimValueOne);
$arrayValueTwo = explode(" ",$trimValueTwo);
$allDiff = array_merge(array_diff($arrayValueOne, $arrayValueTwo), array_diff($arrayValueTwo, $arrayValueOne));
if(array_intersect($arrayValueOne,$allDiff) && array_intersect($arrayValueTwo,$allDiff)){
if(array_intersect($arrayValueOne,$allDiff)){
$highlightArr = array_intersect($arrayValueOne,$allDiff);
$highlightArrValue = array_values($highlightArr);
for ($i=0; $i <count($arrayValueOne) ;$i++) {
for ($j=0; $j <count($highlightArrValue) ; $j++) {
if($arrayValueOne[$i] == $highlightArrValue[$j]){
$arrayValueOne[$i] = "<span>".$arrayValueOne[$i]."</span>";
}
}
}
$strOne = implode(" ",$arrayValueOne);
echo "<p class = \"one\">{$strOne}</p>";
}if(array_intersect($arrayValueTwo,$allDiff)){
$highlightArr = array_intersect($arrayValueTwo,$allDiff);
$highlightArrValue = array_values($highlightArr);
for ($i=0; $i <count($arrayValueTwo) ;$i++) {
for ($j=0; $j <count($highlightArrValue) ; $j++) {
if($arrayValueTwo[$i] == $highlightArrValue[$j]){
$arrayValueTwo[$i] = "<span>".$arrayValueTwo[$i]."</span>";
}
}
}
$strTwo = implode(" ",$arrayValueTwo);
echo "<p class = \"two\">{$strTwo}</p>";
}
}elseif(!(array_intersect($arrayValueOne,$allDiff) && array_intersect($arrayValueTwo,$allDiff))){
if($trimValueOne == $trimValueTwo){
echo"<p class = \"one green\">$trimValueOne</p></p>";
echo"<p class = \"two green\">$trimValueTwo</p></p>";
}
else{
echo"<p class = \"one \">$trimValueOne</p></p>";
echo"<p class = \"two \">$trimValueTwo</p></p>";
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<form method="post" action="">
<textarea type="text" name="value" placeholder="enter first text"></textarea>
<textarea type="text" name="valueb" placeholder="enter second text"></textarea>
<input type="submit">
</form>
</body>
</html>
Python difflib에 기반한 Chris Boulton의 PHP diff 클래스는 좋은 해결책이 될 수 있습니다.
또 다른 솔루션(통합 뷰가 아닌 나란히 비교) : https://github.com/danmysak/side-by-side
문자열 B가 아닌 문자열 A에서 문자를 찾는 매우 간단한 함수를 찾고 있는 분들을 위해 이 빠르고 간단한 함수를 작성했습니다.
function strdiff($a,$b){
$a = str_split($a);
$b = str_split($b);
return array_diff($a,$b);
}
안녕하세요, 이것이 많은 도움이 될 것입니다.
$old_data = "We'll of today's hunt we will find inner zen. You are awesome [TEAM_NAME]! Cleveland has a lot more to offer though, so keep on roaming and find some happiness with Let's Roam!;";
$new_data = "We'll of today's hunt we will find inner zen. Great job today, you are freaking super awesome [TEAM_NAME]! though, so keep roaming Cleveland has a lot more to offer and find happiness on www.letsroam.com!;";
if($old_data) {
$old_words = explode(" " , $old_data);
$new_words = explode(" ", $new_data);
$added_words = array();
$deleted_words = array();
$unchanged_words = array();
foreach($new_words as $new_word) {
$new_word_index = array_search($new_word, $old_words);
// if($new_word == "you"){
// die_r(array());
// }
if( $new_word_index > -1) {
// word already exists
array_push($unchanged_words, $new_word);
unset($old_words[$new_word_index]);
} else {
// word does not already exists
array_push($added_words, $new_word);
}
}
$deleted_words = $old_words;
$added_word_count = count($added_words);
$added_word_characters = strlen(implode(" ", $added_words));
}
die_r(array(
"old_data"=> $old_data,
"new_data"=> $new_data,
"unchanged_words"=> $unchanged_words,
"added_words"=> $added_words,
"deleted_words"=> $deleted_words,
"added_word_count"=>$added_word_count,
"added_word_characters"=>$added_word_characters
));
언급URL : https://stackoverflow.com/questions/321294/highlight-the-difference-between-two-strings-in-php
'sourcecode' 카테고리의 다른 글
MySQL에서 Join을 사용하여 삭제 (0) | 2022.09.26 |
---|---|
PHP 어레이: 개수 또는 크기? (0) | 2022.09.26 |
Google Maps API v3: 모든 마커를 제거하는 방법 (0) | 2022.09.26 |
MySQL 전체 텍스트 부울 모드 와일드카드로 두 글자 단어 검색 (0) | 2022.09.25 |
Laravel 테이블에서 모든 행(소프트 삭제도 가능)을 가져오려면 어떻게 해야 합니까? (0) | 2022.09.25 |