【问题标题】:Compare (diff) strings in two cells by character按字符比较(diff)两个单元格中的字符串
【发布时间】:2015-11-29 17:15:25
【问题描述】:

我在两个具有不同文本的单元格中有文本。我正在尝试识别两个单元格之间的差异(文本之间的差异:添加或丢失的文本)

  1. A1我有一段文字。
  2. B1 包含一个相似的段落,但有细微差别。

我正在尝试识别这些字符串之间的差异,请帮助我识别 两个 使用 VBA 的带有颜色的单元格中的差异

【问题讨论】:

  • 请注意,我的解决方案是使用 A1 和 A2 而不是 An 和 B1。
  • @mynameisammu 我已重新格式化您的问题以使其更具可读性,因为您收到的答案非常出色。供将来参考 (1) 请展示您在回答问题时所做的尝试 (2) 不要提出重复的问题 (3) 更好的格式、标题的选择等可以影响您的问题得到的关注程度。
  • @brettdj 公平地说,我要求他问一个新问题......两次。原因是因为我的第一个答案对于他提供的示例字符串效果很好,然后他跟进了一对更长的字符串,完全满足了我的算法。看来这个问题现在的范围完全不同了,所以我让他问一个新问题,因为之前的答案适用于该问题的上下文并且已经被接受了。

标签: vba excel


【解决方案1】:

我为您的问题提供了解决方案,并已上传包含您的示例字符串对的工作簿。这是workbook

我的代码基于Needleman–Wunsch algorithm,它于 1970 年首次开发,至今仍用于在科学技术中对齐 DNA 序列。但是我修改了算法并添加了额外的后处理来处理您的示例数据字符串对。

这里是如何工作的过程。在 A1 和 A2 中输入要比较的两个字符串。

按 Alt-F8 并运行宏,AlignStrings

结果将显示在单元格 A5 和 A6 中。

请注意,其他示例字符串对可以在表格的下方找到,从单元格 A21 开始。

这是工作簿中完成字符串对对齐和突出显示差异的代码:

Public Sub AlignStrings()
    Dim a() As Byte, b() As Byte, a_$, b_$, i&, j&, d&, u&, l&, x&, y&, f&()
    Const GAP = -1
    Const PAD = "_"

    a = [a1].Text: b = [a2].Text
    [a3:a6].Clear
    [a1:a6].Font.Name = "Courier New"

    ReDim f(0 To UBound(b) \ 2 + 1, 0 To UBound(a) \ 2 + 1)

    For i = 1 To UBound(f, 1)
        For j = 1 To UBound(f, 2)
            x = j - 1: y = i - 1
            If a(x * 2) = b(y * 2) Then
                d = 1 + f(y, x)
                u = 0 + f(y, j)
                l = 0 + f(i, x)
            Else
                d = -1 + f(y, x)
                u = GAP + f(y, j)
                l = GAP + f(i, x)
            End If
            f(i, j) = Max(d, u, l)
        Next
    Next

    i = UBound(f, 1): j = UBound(f, 2)
    On Error Resume Next
    Do
        x = j - 1: y = i - 1
        d = f(y, x)
        u = f(y, j)
        l = f(i, x)
        Select Case True
            Case Err
                If y < 0 Then GoTo left Else GoTo up
            Case d >= u And d >= l Or Mid$(a, j, 1) = Mid$(b, i, 1)
diag:
                a_ = Mid$(a, j, 1) & a_
                b_ = Mid$(b, i, 1) & b_
                i = i - 1: j = j - 1
            Case u > l
up:
                a_ = PAD & a_
                b_ = Mid$(b, i, 1) & b_
                i = i - 1
            Case l > u
left:
                a_ = Mid$(a, j, 1) & a_
                b_ = PAD & b_
                j = j - 1
        End Select
    Loop Until i < 1 And j < 1

    DecorateStrings a_, b_, [a5], [a6], PAD

End Sub


Private Function Max(a&, b&, c&) As Long
    Max = a
    If b > a Then Max = b
    If c > b Then Max = c
End Function


Private Sub DecorateStrings(a$, b$, rOutA As Range, rOutB As Range, PAD$)
    Dim i&, j&

    FloatArtifacts a, b, PAD
    FloatArtifacts b, a, PAD

    rOutA = a
    rOutB = b

    For i = 1 To Len(a)
        If Mid$(a, i, 1) <> Mid$(b, i, 1) Then
            If Mid$(a, i, 1) <> PAD Then
                rOutA.Characters(i, 1).Font.Color = vbRed
            End If
        End If
    Next
    For i = 1 To Len(b)
        If Mid$(a, i, 1) <> Mid$(b, i, 1) Then
            If Mid$(b, i, 1) <> PAD Then
                rOutB.Characters(i, 1).Font.Color = vbRed
            End If
        End If
    Next

End Sub


Private Sub FloatArtifacts(s1$, s2$, PAD$)
    Dim c&, k&, i&, p&
    For i = 1 To Len(s1)
        c = InStr(i, s1, PAD)
        If c Then
            k = 0
            Do
                k = k + 1
                If Mid$(s1, c + k, 1) <> PAD Then
                    If Mid$(s2, c, 1) = Mid$(s1, c + k, 1) Then
                        p = InStr(c + k, s1, PAD)
                        If p < (c + k + 6) And p > 0 Then
                            Mid$(s1, c, 1) = Mid$(s1, c + k, 1)
                            Mid$(s1, c + k, 1) = PAD
                            i = c
                            Exit Do
                        Else
                            i = c + k
                            Exit Do
                        End If
                    Else
                        i = c + k
                        Exit Do
                    End If
                End If
                If c + k > Len(s1) Then Exit Do
            Loop
        Else
            Exit For
        End If
    Next
End Sub

【讨论】:

  • 我无法打开您附加的工作簿
  • 尝试时会发生什么?
  • 不客气。这是一个引人入胜的问题……非常具有挑战性。我尝试了很多东西,做了很多研究。我最终基于 1970 年的一种名为 Needleman-Wunsch 的算法奠定了解决方案的基础,该算法仍然主要用于对齐生物学中的 DNA 序列。但这还不够,我需要对其进行更改,然后进一步处理结果以使用您的示例字符串对。
  • 真的不敢相信它可以按照我的要求工作.....我永远不会忘记我生命中的这种帮助,,,,,
  • @Excel Hero 在这种情况下请帮忙
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多