【问题标题】:Comparing elements of two strings比较两个字符串的元素
【发布时间】:2013-09-26 22:23:26
【问题描述】:

我开发了以下代码来比较 A 列和 D 列中的两个单元格(字符串),如果发现部分匹配,则在相应的 B 单元格中记下 D 单元格值。

Sub CompareAndGuess()
Dim strLen, aux As Integer
Dim max1, max2 As Long
Dim str As String

Range("A1").Select
Selection.End(xlDown).Select
max1 = ActiveCell.Row
Range("D1").Select
Selection.End(xlDown).Select
max2 = ActiveCell.Row

For a = 2 To max1
    str = Cells(a, 1)
    str = StrConv(str, vbUpperCase)
    strLen = Len(str)
    aux = strLen

    For l = 3 To strLen
         For d = 2 To max2
             If Cells(d, 4) = Left(str, aux) Then
                Cells(a, 2) = Cells(d, 4)
                Exit For
            ElseIf Cells(d, 4) = Right(str, aux) Then
                Cells(a, 2) = Cells(d, 4)
                Exit For
            End If
        Next d

        aux = aux - 1
        If Cells(a, 2) <> "" Then
            Exit For
        End If
    Next l
     Cells(a, 2).Select
Next a
End Sub

谁能帮我找出问题出在哪里,因为当我运行它时,代码只能猜对 50 行中的一行,而它应该至少匹配 40 左右。

拜托,我真的找不到那里的错误。如果您愿意,请随时为我的问题提出另一种解决方案。

我正在分析的数据样本是: 有错别字的名字:-

Jatiuca
Pajuara
Poco
Santa Luzia
Pajucara
Domingos Acacio
Jaragua
Stella Maris
P Verde
Tabuleiro dos Martin
Gruta Lourdes
Brasilia
Centro Historico
Monumento
Tabuleiro dos Martins

要在此列表中搜索的拼写错误名称:-

JARAGUÁ
TABULEIRO DO MARTINS
CENTRO
BRASÍLIA
CACIMBAS
JATIÚCA
CAITITUS
PAJUÇARA
CANAÃ
PONTA VERDE
CANAFÍSTULA
POÇO
CAPIATÃ
CAVACO
SANTA LÚCIA

【问题讨论】:

  • VB 有 InStr 函数,这里可能会感兴趣...
  • 是的,我也考虑过这种方法,感谢您的提醒。我会试一试,但我仍然想知道我的代码有什么问题......
  • 因为与1(一)相似?如果是这样,好点。谢谢!
  • 您能否提供任何具有预期结果的样本数据
  • 伙计们,我找到了正确的方法。我会在这里发帖只是为了向大家和任何在谷歌上搜索的人展示。再次感谢大家!虽然我自己认为该方法非常有用(特别是“InStr”提示!!!)

标签: string vba excel compare


【解决方案1】:

在大家的帮助下,我找到了正确的方法。 这里是:

        If InStr(1, Cells(d, 4), Left(str, aux)) = 1 Then
            Cells(a, 2) = Cells(d, 4)
            Exit For
        ElseIf InStr(Cells(d, 4), Right(str, aux)) + strLen - aux = strLen Then
            Cells(a, 2) = Cells(d, 4)
            Exit For
        End If

【讨论】:

  • 这似乎非常不可靠,我错了还是会替换包含列表中单词的第一个或最后 3 个字母的任何单词?为什么即使两者都循环不同的长度,为什么不只对第一个和最后三个字母做一个循环呢?
  • 事实上,这似乎并不总是有效。我不只搜索 3,因为找到 4、5、6 等序列字母比只找到 3 个要好,因为两个或多个单词可能有这 3 个而不是 4、5、6 等。
  • 但它可能会用错误的单词替换错误的单词,因为它确实包含 3,即使名称大不相同。
【解决方案2】:

很高兴您使用 InStr 函数自己解决了问题。您的代码运行不佳的原因是您将名称的缩短版本与完整版本进行比较。使用以下内容修改您之前的代码会发现更多匹配项。

            If Left(Cells(d, 4), aux) = Left(str, aux) Then
                Cells(a, 2) = Cells(d, 4)
                Exit For
            ElseIf Right(Cells(d, 4), aux) = Right(str, aux) Then
                Cells(a, 2) = Cells(d, 4)
                Exit For
            End If

【讨论】:

  • 我相信这只有在有错别字和没有错别字的单词长度相同时才有效。什么没有发生。还是谢谢
  • @BrunoMartins 它只需要比较单词的开头或结尾,在您的示例数据上进行尝试,它找到了 10 个匹配项,但没有找到 POÇO。
  • 我目前正在使用类似于您在此处发布的内容,但在每个比较的左侧没有“辅助”并且使用不同的变量,因此我运行所有可能的组合以找到最佳组合匹配。
【解决方案3】:

这绝对是未经测试

我明天会重写并清理它,但这是真正知道您匹配正确单词的基本方法。这可能需要更长的时间,我明天会加快速度,但现在这是测试单词有效性的壁橱方法

'Go through all possibly typod words
For each rngTestCell in Range("yourlist")

   'For each possibly typod word test if against every correct value
    For each rngCorrectedValue in Range("ListOfCorrectValues")

        'start by testing length to weed out most values quick
        'Test any words that are within 3 letters of each other, can be less
        'could add a tet for first and last letters match also before starting 
        'to match every letter also, just a top level weeding of words
        If (Len(rngTestCell) - Len(rngCorrectedValue)) < 3 Then

           'loop each letter in the words for match keep a record of how many are matched
           for i = 1 to Len(rngTestCell)

                If rngTestCell.Character(i,1) = rngCorrectedValue.Characters(i,1) Then
                     NumberOfMatches = NumberOfMatches + 1
                End If

            next i

            'if enough of the letters match replace the word, this will need updating because
            'i feel using a ratio of more then 10% of the words match then replace
            'but for now if more then 2 letters don't match then it isn't a match
            If (Len(rngTestCell) - NumberOfMatches) > 2 Then 'Less then 2 letters are different
                rngTestCell.Offset(,1).Value = rngCorrectedValue.Value
                Exit Loop
            End If

        End If

    Next rngCorrectedValues

Next rngTestCell 

【讨论】:

  • 对于匹配语言进行优化的 Smith-Waterman 算法的修改版本可能是最好的方法吗?您可能对每个匹配的字符使用 1,对每个不匹配、插入或删除的字符使用 -1。也许过度设计解决方案。
  • @GrahamAnderson 这完成得非常快,更像是一个概念证明,但到目前为止,这是唯一一个不会用CANAÃ替换CANAFISTULA的答案,尽管CANAFISTULA应该被替换使用CANAFÍSTULA,更进一步,如果正确的单词CANAFÍSTULA 在列表中,它将被替换为CANAÃ 这个例子不会有这个错误。这样做的目的是确保不要错误地更换东西。我看不出这是如何过度设计任何东西的,如果有更简单的方法可以获得相同的结果,那么可以,但这是我能想到的最简单的方法。
  • 当正确的名称 CANAFÍSTULA 在正确的列表中时,我的方法和我怀疑布鲁诺的方法都不会用 CANAÃ 替换 CANAFISTULA,这是因为循环在第一个(因此最长的)匹配之后终止。我确实认为你的方法更健壮。抱歉,由于过度工程言论造成的任何冒犯,我的意思是考虑使用 Smith-Waterman 类型算法。这些通常用于比对蛋白质或核酸序列。它将测试每对字符串之间的所有可能的完全/部分匹配,因此可以认为有点多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-08
  • 2021-09-01
  • 1970-01-01
  • 2011-08-04
  • 1970-01-01
  • 2013-05-08
相关资源
最近更新 更多