ExcelTip.Net留存知识帖 ---【注:附件之前被网盘供应商清空后,现已修复-现已修复-现已修复为本地下载!】
现在位置:首页 > 我的酷贴 > Excel VBA > 如何快速地从已知地址库中查找到包含关键词语的答案?

如何快速地从已知地址库中查找到包含关键词语的答案?

作者:绿色风 分类: 时间:2022-08-18 浏览:144
楼主
chenlifeng
我通过亲身遇到的问题,并把它解决了,现在总结如下:
问题:
    输入一个表示地名的几个字,如“湖南”、“湖南省”、“山东聊城”、“山东  聊城1”、“13广东 大良镇”等(前后可有干扰字符),如何在地址库中找到与之最符合的一个或几个详细地址?(相当于百度功能来查找地址)
    如刚才举例的几个关键词语的答案依次为:“湖南省”、“湖南省”、“山东省聊城市”、“广东省佛山市顺德区大良街道办事处”,总之,关键证词词语包括到了哪一个行政级别,地址答案就到那一级别,不往下把更详细的显示。


答案:
    附件1(名称:关键字中排干扰,地址库里显英豪):已经成功调试,是最快、最新能排干扰的查找方式。
    在窗体输入口中输入想要查询的内容,点击“查找”,即可在一秒内找到最合适的答案(关键词语越详细越快,当只有一个字时,由于要产生的答案太多,速度较慢;而输入地名中的连续两个字,速度快到只用半秒就见答案);

    附件2(名称:只排除后面干扰、速度时快时慢):成功调试,速度时快时慢,当输入地址表中靠上面的行中的地址时,速度快,越靠下面的行、越靠后面的列,速度越慢。原因是它查找的方式是以行为单位查找匹配的, 而附件1是以列为查找依据、且分5个行政区,故最多只查找5列,速度自然跟上了。有关这两者的代码,见后;
   
    附件3(名称:不紧不慢):不排除干扰,有干扰即为打不到答案。查找时,每次总是用时三秒;但思路非常有意思,代码简短,乃一朋友所作。

下面第一段代码为附件1中的部分代码,是与附件2唯一不同的地方,用的是列的方法查找,速度最快:
  1. For Each 字典2元素 In 字典2
  2.     For I = 1 To UBound(Arr)
  3.         If InStr(字典2元素, Arr(I, 1)) > 0 Then
  4.            字典2元素变体 = Replace(字典2元素, Arr(I, 1), "")
  5.            If Len(字典2元素变体) = 0 Then If Not 字典3.Exists(Arr(I, 1)) Then 字典3.Add Arr(I, 1), "": Exit For '即答案只是省名罢了
  6.            K = 重复值所在的最大行数(Range("a" & I & ":a" & Range("A65536").End(xlUp).Row), Range("a" & I).Value)
  7.                For J = I To K
  8.                    If InStr(字典2元素变体, Arr(J, 2)) > 0 Then
  9.                       If Mid(Replace(字典2元素变体, Arr(J, 2), ""), 1, 4) = "塔城地区" Then
  10.                          J = 2899: L = 2905: 字典2元素变体 = Replace(字典2元素变体, Arr(J, 2), ""): 字典2元素变体 = Replace(字典2元素变体, "塔城地区", ""): GoTo line3
  11.                       ElseIf Mid(Replace(字典2元素变体, Arr(J, 2), ""), 1, 5) = "阿勒泰地区" Then
  12.                          J = 2906: L = 2912: 字典2元素变体 = Replace(字典2元素变体, Arr(J, 2), ""): 字典2元素变体 = Replace(字典2元素变体, "阿勒泰地区", ""): GoTo line3
  13.                       End If

  14.                       字典2元素变体 = Replace(字典2元素变体, Arr(J, 2), "")
  15.                      
  16.                       If Len(字典2元素变体) = 0 Then If Not 字典3.Exists(Arr(I, 1) & Arr(J, 2)) Then 字典3.Add Arr(I, 1) & Arr(J, 2), "": Exit For '即答案只是省和市名罢了
  17.                       L = 重复值所在的最大行数(Range("b" & I & ":b" & K), Range("b" & J).Value)
  18. line3:
  19.                          For M = J To L
  20.                              If InStr(字典2元素变体, Arr(M, 3)) > 0 Then
  21.                                 字典2元素变体 = Replace(字典2元素变体, Arr(M, 3), "")
  22.                                 If Len(字典2元素变体) = 0 Then If Not 字典3.Exists(Arr(I, 1) & Arr(J, 2) & Arr(M, 3)) Then 字典3.Add Arr(I, 1) & Arr(J, 2) & Arr(M, 3), "": Exit For    '即答案只是省、市、乡名罢了
  23.                                 N = 重复值所在的最大行数(Range("C" & J & ":C" & L), Range("C" & M).Value)
  24.                                 For O = 4 To Range("D" & N).End(xlToRight).Column
  25.                                     If InStr(字典2元素变体, Arr(N, O)) > 0 Then
  26.                                        If Not 字典3.Exists(Arr(I, 1) & Arr(J, 2) & Arr(M, 3) & Arr(N, O)) Then 字典3.Add Arr(I, 1) & Arr(J, 2) & Arr(M, 3) & Arr(N, O), "": Exit For   '即答案已是省、市、乡、镇了
  27.                                     ElseIf InStr(Arr(N, O), 字典2元素变体) > 0 Then
  28.                                        If Not 字典3.Exists(Arr(I, 1) & Arr(J, 2) & Arr(M, 3) & Arr(N, O)) Then 字典3.Add Arr(I, 1) & Arr(J, 2) & Arr(M, 3) & Arr(N, O), "": Exit For   '即答案已是省、市、乡、镇了
  29.                                     End If
  30.                                 Next
  31.                              Exit For
  32.                              ElseIf InStr(Arr(M, 3), 字典2元素变体) > 0 Then
  33.                                 If Not 字典3.Exists(Arr(I, 1) & Arr(J, 2) & Arr(M, 3)) Then 字典3.Add Arr(I, 1) & Arr(J, 2) & Arr(M, 3), "": Exit For    '即答案只是省、市、乡名罢了
  34.                              End If
  35.                          Next
  36.                   Exit For
  37.                   ElseIf InStr(Arr(J, 2), 字典2元素变体) > 0 Then
  38.                       If Not 字典3.Exists(Arr(I, 1) & Arr(J, 2)) Then 字典3.Add Arr(I, 1) & Arr(J, 2), "": Exit For '即答案只是省和市名罢了
  39.                   End If
  40.               Next
  41.         Exit For
  42.         ElseIf InStr(Arr(I, 1), 字典2元素) > 0 Then
  43.           If Not 字典3.Exists(Arr(I, 1)) Then 字典3.Add Arr(I, 1), "": Exit For '即答案只是省名罢了
  44.         End If
  45.     Next
  46. Next
附件2中的部份代码,与附件一的作用是一样的,但速度较慢:
  1.   zzz = 0   '初始化zzz,zzz有其妙用处
  2.     fo = 2    '初始华fo,它与ZZZ一样代表源地址库中的行数。
  3. line4:  '标志4

  4. For Each abc In di  'di 就是所输入的TEXTBOX1中的内容,进行了整理后的内容,每个字符中间用星号隔开。可能会循环一次或多次
  5.     cde = "*"
  6.     For bcd = 1 To Len(abc)
  7.         cde = cde & Mid(abc, bcd, 1) & "*"
  8.     Next
  9.    
  10.     For ufo = fo To Sheets("全国地址库").Range("A65536").End(xlUp).Row
  11.       For ee = 1 To Sheets("全国地址库").Range("A" & ufo).End(xlToRight).Column
  12.         If Not dic.Exists(Arr(ufo, ee)) Then
  13.             dic.Add Arr(ufo, ee), ""    'dic 是源数据 ,现在被定义为字典,向里面写数据,这一句是把每行的数据收集起来,再到下面做判断,故每一行有多少就收集多少到字典中。
  14.             ppp = Join(dic.KEYS, "")
  15.             If ppp Like cde Then '把上面收集来的数据与输入的内容比较判断,一旦符合就退出这个UFO循环, 进入下一个环节(给地址查找行政划分的单位)否则清空字典,再从上面来过。
  16.                GoTo line3
  17.             Else:
  18.                 If ee > 3 Then dic.Remove Arr(ufo, ee) 'dic.RemoveAll
  19.             End If
  20.         End If
  21.       Next
  22.         dic.RemoveAll
  23.         zzz = zzz + 1        '这里的累加,是为了后面作准备:万一下面这句是属于误判,则根据ZZZ再返回到刚才收集数据的下一行进行,而不必再从头再来,以致死循环。至于下句会出现误判的原因:如输入“蓬安”,四川省有个蓬安县,但就在这个答案的上一行有两个县(各占一单元格),一个叫太蓬乡,另个是固安乡,两者合一起就饱含了刚才的“蓬安”两字,符合下面的要求,但最后会导致答案为空。
  24.     Next
  25.    
  26. '*******下面意思是,给上面查找到的结果,赋上正确的行政划分地址,有行政地址的则免********
  27. line3:
  28.     u = abc   'abc即前面 进行了重复排查后的字典di中的元素,也是手动输入后整理出来的结果
  29.     For Each gg In dic
  30.         If InStr(u, gg) > 0 Then   '源数据中的行政地址与 U(或abc) 中的作一一对比,如果源数据的某一个数据被包括在U中,则
  31.            u = Replace(u, gg, "")  '发现两者存在重复,清除U中的内容,
  32.            dic.Remove gg           '亦清除字典dic中的重复内容
  33.            If Len(u) = 0 Then  '这里是指全部把dic中的内容匹配完了,结果为空,说明输入的内容正好是一个完整的行政划分。
  34.               If Not ddc.Exists(abc) Then ddc.Add abc, ""    '向新字典ddc 中写abc,这里表示所输入部分正好是一个完整的行政划分
  35.            End If
  36.         End If
  37.     Next

  38.     If Len(u) > 0 Then               '没有清除完的abc内容
  39.        For Each gg In dic
  40.            If InStr(gg, u) > 0 Then  '输入数据u与剩余的源数据gg作一一对比,与上面的一一对比正好相反 '如果存在重复,则:
  41.               x = Mid(gg, InStr(gg, u) + Len(u), Len(gg) - InStr(gg, u) + Len(u) - 1) '提取源数据GG中比输入数据多余的部分
  42.               y = abc & x        '再把多余的这部分与已经从最先输入的TEXTBOX1内容得了的答案di合并
  43.               If Not ddc.Exists(y) Then ddc.Add y, ""     'ddc 向新字典中写入 “所输入的TEXTBOX1内容加 所缺少内容”
  44.               Exit For  '找到后,给上述字典赋值完后,退出本轮的循环,进行新一个ABC的循环,如果字典DI有多个元素的话。
  45.            End If
  46.        Next
  47.     End If
  48. Next
  49.        If zzz = Sheets("全国地址库").Range("A65536").End(xlUp).Row Then MsgBox "没找到": Exit Sub:
  50.        If UBound(ddc.KEYS) + 1 = 0 Then:   fo = fo + zzz: GoTo line4 '这里的确UBound(ddc.keys) + 1 = 0表示数字是空?!
  51.        If UBound(ddc.KEYS) = 0 And Right(CC, 1) = "市" Then
  52.           For Each gg In ddc
  53.               If InStr(gg, Mid(CC, 1, Len(CC) - 1)) = 0 Then CC = Mid(CC, 1, Len(CC) - 1): xh = 1: ddc.RemoveAll: GoTo line0 '本行作用在于:把不是“市”的行政单位当成“市”时,去掉“市”再运行一次。如“新化县”存在,“新化市”不存在。
  54.           Next
  55.        End If
附件三的代码部分,思路不一样:
  1. For i = 2 To UBound(brr)
  2.                 If brr(i) <> "" Then
  3.                     lng = InStr(brr(i), .TextBox1) + Len(.TextBox1) - 1
  4.                     If Right(Left(brr(i), lng), Len(.TextBox1)) = .TextBox1 Then
  5.                         d(Left(brr(i), lng)) = ""
  6.                     End If
  7.                 Else
  8.                     Exit For
  9.                 End If
  10.             Next

不紧不慢.rar
只排除后面干扰、速度时快时慢.rar
关键字中排干扰,地址库里显英豪.rar
2楼
angel928
好长的代码。
3楼
chenlifeng
是呀,有点长,全部是窗体中的。
花了几个星期才整理学会的。学会了这些,感觉自己的水平又有一个大的提升了……

4楼
chenlifeng
提出最终的修正:
以上的思路中,第一、二个发现了可完善的地方,我对窗体中的一段代码更新如下,主要是第11-13行作了更改,使之有及时更新功能了:
  1. Private Sub UserForm_Initialize()
  2.     Application.Volatile
  3.     Dim i&, 最初字典, J&, 四列联合$

  4.     Set 最初字典 = CreateObject("scripting.dictionary")
  5.     arr = Sheets("全国地址总库详备").UsedRange.Value
  6.     For i = 2 To UBound(arr)
  7.         四列联合 = arr(i, 1) & arr(i, 2) & arr(i, 3) & arr(i, 4)
  8.         最初字典(四列联合) = 0
  9.         For J = 5 To UBound(arr, 2)
  10.             If IsEmpty(arr(i, J)) Or arr(i, J) Like "*没找到*" Then
  11.             Else    'Exit For
  12.                 最初字典(四列联合 & arr(i, J)) = 0
  13.             End If
  14.         Next
  15.         四列联合 = ""
  16.     Next
  17.     原始数组 = 最初字典.keys
  18.     最初字典.RemoveAll: Set 最初字典 = Nothing
  19.     TextBox2.Value = ""
  20. End Sub

免责声明

有感于原ExcelTip.Net留存知识的价值及部分知识具有的时间限定性因素, 经与ExcelTip.Net站长Apolloh商议并征得其同意, 现将原属ExcelTip.Net的知识帖采集资料于本站点进行展示, 供有需要的人士查询使用,也慰缅曾经的论坛时代。 所示各个帖子的原作者如对版权有异议, 可与本人沟通提出,或于本站点留言,我们会尽快处理。 在此,感谢ExcelTip.Net站长Apolloh的支持,感谢本站点所有人**绿色风(QQ:79664738)**的支持与奉献,特此鸣谢!
------本人网名**KevinChengCW(QQ:1210618015)**原ExcelTip.Net总版主之一

评论列表
sitemap