首页 新闻 搜索 专区 学院

比较2句话的不同

1
悬赏园豆:100 [已解决问题] 解决于 2013-01-21 10:36

一句话A ,在A上进行增删改查后变为B,找到B中修改的部分高亮显示,求原理或者代码

老孟Flutter的主页 老孟Flutter | 初学一级 | 园豆:55
提问于:2013-01-15 10:39
< >
分享
最佳答案
1

hi guy.
这个问题如果单纯对比原始的串和最终串的话,没有任何意义,举个简单的例子,我有字串a="abcd",把"ab"删除,剩下"cd"。用上边的方法一个都不可行。再比如把"cd"插入到a串最前得到"cdabcd",这时候应该把前边的"cd"设置高亮,按照前边的方法也无法做到。所以我认为需要记录操作步骤来做。而“增删改”其实就只是“增”和“删”,其中“改”可以通过前两个操作来体现。那么就实现记录“增”和“删”的操作就行了。
例如函数:add(string target,int idx,string str)  //在指定串target的指定位置插入串str
     del(string target,int idx,int len)    //删除指定串target中从idx开始,长度为len的子串
通过这样的定义可以完整保留操作信息,例如有串a='abcd'。对a删除'bcd',这时候调用
     del(a,1,3)
而在del函数内部可以记录下串target的操作是'delete',从索引 1 开始,长度为 3。这样子在显示的时候,只要把串a中从1开始长度为3的一部分设置高亮即可。再比如在串a中插入一个一样的串"abcd",得到b="abcdabcd",这个时候按照上边的办法无法区分哪个是新的。而调用函数
     add(a,0,"abcd")
这样子就可以设置最终串b中从索引0开始,长度为4的子串高亮。
我想这样足以解决任何问题,多个操作的时候也可以实现。希望对楼主有帮助。:)

收获园豆:100
月窟仙人 | 菜鸟二级 |园豆:383 | 2013-01-15 21:20

非常感谢你,首先我只能得到2个字符串,其次这个功能使我们公司的一个管理系统中的小功能,管理需要对比2个字符串,字符串是一句话,可能是英文、法文、俄语、西班牙语、葡萄牙语,如果是删除的部分我们理想的效果是把删除的补充出来并特殊显示,增加的就高亮显示,功能很类似SVN的Diff功能只不过SVN是逐行比较,我们需要逐个单词比较,从目前的情况来看,这个功能不怎么好实现,主要是没有算法,如果谁有好的想法希望告知下。

老孟Flutter | 园豆:55 (初学一级) | 2013-01-16 15:18

@meng5619: 如果不能得到操作步骤,仅仅得到最后的结果,最后作一下对比,可能反映不了真实情况,但还是能够标识出区别的。但必须要有约定,比如a="abc",b="aabc",这个情况下可以认为是在a字符串的最前边插入了'a',也可以认为是字符'b'之前插入了'a'。我们就约定a中的一个字符在b中第一次出现的位置是原来的字符串,以后出现更多的是插入的。因此上面应该是认为在字符'b'之前插入了'a'。再例如a="xyzkln",b="xklnyz",这个时候可以认为是"yz"被删除并插入到末尾,也可以认为"kln"被删除并插入到"x"的后面。这里就约定a串中的"x"与"y"原先没有字符串,那b串中它们之间的字符串是被插入的,而后面的"kln"被删除了。按照这两个约定,我尝试用javascript来写下算法代码。
原理:用两个队列维护添加和删除的记录分别为addIdx,delIdx。addIdx结构为start和end两个属性。delIdx结构为idx和word两属性。设置两个指针,分别从a,b两个字符串的索引0开始,对于a中的每一个字符(或者单词),在b中找第一次出现的索引,如果能找到,并且相对距离未改变,则两个指针同时前进,若相对距离改变了则之间的串为插入串,放到addIdx中,例如上面的"kln",如果找不到,则a串中的当前字符在b串中被删除。记录删除的字符和索引。
其实这个比较难说清楚,要有图就很容易看清。下面是javascript代码:

 1 function diffStr(a,b){
 2     var i,j,k,l;
 3     for(i=j=0;i<a.length&&j<b.length;i++){
 4     k=j;
 5     while(b.charAt(k)!=a.charAt(i) && k<b.length){
 6         k++;
 7     }
 8     if(k<b.length){
 9         if(j!=k) addIdx.push({start:j,end:k-1});
10         j=k+1;
11     }
12     else{
13         delIdx.push({idx:j,word:a.charAt(i)});
14     }
15     }
16     if(j<b.length){
17     addIdx.push({start:j,end:b.length-1});
18     }
19     while(i<a.length){
20     delIdx.push({idx:i});
21     i++;
22     }
23 }

这个函数的作用就是通过上边描述的算法产生addIdx和delIdx。这样所有信息都有了。之后的事情便是打印出来,我这边写了一个插入的高亮代码,删除的原理也一样,楼主可以自己实现。

1 function recOut(str,offset){
2     if(n=addIdx.shift()){
3     return str.slice(0,n.start-offset).concat('<span class=\'highlight\'>'+str.slice(n.start-offset,n.end-offset+1)+'</span>').concat(recOut(str.slice(n.end-offset+1),n.end+1));
4     }
5     else
6         return str;
7 }

其实就是不断出队列,再递归直到队空。下面是测试和效果:

1 var a="不以结婚为目的的谈恋爱都是耍流氓";
2 var b='毛主席说:\'不以为目的谈恋人都是耍流氓流氓\'';
3 addIdx=[];
4 delIdx=[];
5 diffStr(a,b);//算法主要部分
6 var finalStr = recOut(b,0);
7 document.write(finalStr);

这时候的addIdx值:[{start:0,end:5},{start:13,end:13},{start:19,end:21}],
delIdx的值:[{idx:8,word:"结"},{idx:8,word:"婚"},{idx:11,word:"的"},{idx:13,word:"爱"}]。
结果:

毛主席说:'不以为目的谈恋都是耍流氓流氓'

应该说效果全都有了,再加上删除的就完美了。我晕,写了这么多,可以写一篇文章了,有时间整理一下。另外楼主说的多语言问题也不存在,只要划分好粒度即可,例如我这是中文,你对日文也一样的,英文的话更方便啦。要是有问题再回复我吧,写了这么多希望能帮上忙:)

月窟仙人 | 园豆:383 (菜鸟二级) | 2013-01-17 01:31

@月窟仙人: 非常感谢你,这几天忙别的事了,先说声抱歉,你的方法我还没有做相应的测试,我这有一个算法,虽然有些不完美,不过已经满足绝大部分情况了,和大家分享下:

public static string GetCompare(string stringNameA, string stringNameB)
{
if (string.IsNullOrEmpty(stringNameA))
{
return " <strong class="Highlight">" + stringNameB + "</strong>";
}
string[] stringNameAS = stringNameA.Split(' ');
string[] stringNameBS = stringNameB.Split(' ');
int a = stringNameAS.Length;
int b = stringNameBS.Length;
int count = a >= b ? b : a;
string stringNameC = "";
int m = 0;
int n = 0;
for (int i = 0; i < b; i++)
{
if (m >= b)
{
break;
}
if (n == a)
{
n = a - 1;
}
if (n > a)
{
for (int x = n; x < b; x++)
{
stringNameC = stringNameC + " <strong class="Highlight">" + stringNameBS[x] + "</strong>";
}
break;
}
if (stringNameAS[n] == stringNameBS[m])
{
stringNameC = stringNameC + " " + stringNameBS[m];
}
else
{
for (int k = m; k < b; k++)
{
if (stringNameBS[k] == stringNameAS[n])
{
int z = 0;
for (int y = 0; y < k; y++)
{
if (stringNameBS[y] == stringNameBS[k])
{
z = 1;
break;
}
}
if (z == 0)
{
stringNameC = stringNameC + " " + stringNameBS[k];
}
else
{
stringNameC = stringNameC + " <strong class="Highlight">" + stringNameBS[k] + "</strong>";
}
m = k;
break;
}
else
{
int g = 0;
for (int j = n; j < a; j++)
{
if (stringNameBS[k] == stringNameAS[j])
{
n = j;
m = k;
g = 1;
break;
}

}
if (g == 1)
{
stringNameC = stringNameC + " " + stringNameBS[k];
break;
}
else
{
stringNameC = stringNameC + " <strong class="Highlight">" + stringNameBS[k] + "</strong>";
}

}
}
}
m++;
n++;
}

return stringNameC.Trim();
}

这段代码是别人给我的,其中的原理写字真的很难说清楚,可能是我语言表达有问题,哈。其实我们这还有一种算法,和二分法有些类似,不过代码实现有点困难,反正我写不出来,如果谁擅长写这种逻辑代码可+我QQ781238222。好了,感谢大家。多多交流。园豆给你,希望能多多帮助新人。

老孟Flutter | 园豆:55 (初学一级) | 2013-01-21 10:34
其他回答(2)
0
        临时变量
        try
        {
            using(事务上下文(可以自己实现事务资源管理器))
            {
                修改对象A

                    转变

               使其转换为B的特征


                   用变量记录下来修改的部分为哪些

                   事务提交

                       记录下来的变量就为修改的(高亮显示)
            }   




        }
        catch (Exception)
        {
            事务自动回滚(变量还变回原来的)不会高亮
        }
        finally
        {

        }
田麦成 | 园豆:2004 (老鸟四级) | 2013-01-15 10:52
0
            string A = "博客园";
            string B = "第一个位置加1博客第二位置园";
            IEnumerable<char> cc = B.Except(A);
            string C = string.Join("", B.Select(s => cc.Contains(s) ? string.Format("<font style='color:{1}'>{0}</font>", s, "red") : s.ToString()));
Qlin | 园豆:2403 (老鸟四级) | 2013-01-15 10:54

非常感谢你,我测试了下,目前发现一种情况不能满足我的情况,如A=“ABCD” ,B="ABCDD",即添加一个单词时,这个单词不能和A中重复,否则无法找出。

支持(0) 反对(0) 老孟Flutter | 园豆:55 (初学一级) | 2013-01-15 11:14

@meng5619: 

那你 for循环遍历 一下

string A = "ABCD";
            string B = "ABCDD";
            List<int> Change = new List<int>();
            for (int i = 0; i < B.Length; i++)
            {
                if (A.Length > i)
                {
                    if (A[i] != B[i])
                    {
                        Change.Add(i);
                    }
                }
                else
                {
                    Change.Add(i);
                }
            }
            string C = string.Join("", B.Select((s, i) => Change.Contains(i) ? string.Format("<font style='color:{1}'>{0}</font>", s, "red") : s.ToString()));
支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-15 11:42
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册