找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 62437|回复: 20

[文本处理] 【已解决】如何用 递归哈希算法 或 匹配表算法 搜索字符串

[复制链接]
发表于 2023-3-29 18:41:36 | 显示全部楼层 |阅读模式
本帖最后由 思想之翼 于 2023-4-9 05:37 编辑

https://zhuanlan.zhihu.com/p/389419957
该文阐述字符串搜索算法有  朴素算法   Rabin-karp算法(递归哈希)   Kruth-Morris-Pratt算法(匹配表),这三种算法,时空复杂度犹如云泥之别。
文章结论:由于在文本字符串中遍历时,不管模式字符串多长,每次计算量只涉及一次旧值的去除和一次新值的添加,Rabin Karp算法最适合用于模式字符串非常长的情况,比如长句子在论文中的查重。
我曾用VBS代码解决类似字符串匹配问题,运行速度之慢,难于言表。
限于网络难以搜寻到类似参考代码,故特举例,恳请各位老师指点(不拘泥于上述列举算法)。

例:文本A.txt 记录字符串
W
A
D
C
B
A
D
C
B
A


1.首先,读取A.txt文本字符串,并反转文本字符串为:ABCDABCDAW
2.其次,始终以A为起点,选择模式字符串。本例中,ABCDA 在文本字符串中存在2个及以上,且为最长相同字符串,故确定 ABCDA 为模式字符串。
3.然后,在文本字符串中,提取模式字符串的前缀。
4.结果:本例提取的前缀为D,写入文本B.txt  ;如有多个模式字符串的前缀,则不去重,依次竖排(另起一行)写入文本B.txt。

评分

参与人数 1PB +2 收起 理由
Batcher + 2 感谢给帖子标题标注[已解决]字样

查看全部评分

发表于 2023-3-29 19:04:40 | 显示全部楼层
http://www.bathome.net/thread-65332-1-1.html

感觉和这个有点相似?

评分

参与人数 1技术 +1 收起 理由
思想之翼 + 1 非常感谢你不吝赐教

查看全部评分

发表于 2023-3-29 19:47:25 | 显示全部楼层
是不是介样子呢?

  1. $t='WADCBADCBAFEGFLIFABCDEFABCDEFALI';
  2. $f=$t.ToCharArray();
  3. [array]::Reverse($f);
  4. $e=-join($f);

  5. $d=[regex]::Matches($e, "(?s)(.)((?:(?!\1).)+)\1(?=\2\1){1,}").value;

  6. # 这是获取最长一个为 :输出B
  7. if($null -ne $d -and $d.Length -gt 0){
  8.         $s=[Linq.Enumerable]::Max($d, [func[object,int]]{param($i); $i.Length;});
  9.         $d.Where{$_.Length -eq $s}.Foreach{$_.SubString($_.Length-2,1)}
  10. }

  11. # 这是获取每一个为 ;输出 B;D
  12. if($null -ne $d -and $d.Length -gt 0){
  13.         $d.ForEach{$_.SubString($_.Length-2,1)}
  14. }

复制代码

评分

参与人数 1技术 +1 收起 理由
思想之翼 + 1 感谢

查看全部评分

发表于 2023-4-1 22:45:29 | 显示全部楼层
  1. @if(0)==(0) echo off
  2. type a.txt | cscript //nologo //e:jscript "%~f0" > b.txt
  3. pause & exit
  4. @end

  5. var str = WSH.StdIn.ReadAll().replace(/\s/g, '');
  6. var Len = str.length;
  7. var flag = false;

  8. for (var i = Len-1; i > 0; i--) {
  9.     var key = str.substr(Len-i);
  10.     for (var j = 0; j < Len-i; j++) {
  11.         if (str.substr(j, i) === key) {
  12.             flag = true;
  13.             WSH.Echo(str.substr(i+j, 1));
  14.         }
  15.     }
  16.     if (flag) break;
  17. }
复制代码

评分

参与人数 1技术 +1 收起 理由
思想之翼 + 1 感谢

查看全部评分

 楼主| 发表于 2023-4-7 23:24:32 | 显示全部楼层
回复 4# WHY
感谢!有一点疑惑:计算1列2000行的数据,该代码耗时22秒,VBS代码却只耗时0.07125秒,老刘一号不是说:“随便换个编译型语言效率就可以薄纱vbs”吗?
发表于 2023-4-8 18:41:22 | 显示全部楼层
回复 5# 思想之翼
计算1列2000行 应该不需要22秒  一楼的意思应该是要匹配的字符总是第一位开始 是这样吗
 楼主| 发表于 2023-4-8 20:27:26 | 显示全部楼层
本帖最后由 思想之翼 于 2023-4-8 21:34 编辑

回复 6# terse
您好!是的。

递增:A(有重复)  AB(有重复)  ABC(有重复)  ABCD(有重复) ABCDA(有重复)  ABCDAB(无重复)...  找到ABCDA有重复,且最长字符串。

从总字符串的一半(奇数则+1)开始递减,是否更快?
ABCDAB(无重复)   ABCDA(有重复)... 找到ABCDA有重复,且最长字符串。

实际运用中,没有极端情况,比如:AAAAAAAAAAAAAA 或者 ABABABABABABAB 或者 ABCABCABCABC ...
发表于 2023-4-8 22:04:30 | 显示全部楼层
回复 5# 思想之翼


    把你测试用的 2000 行的文本放到网盘,分享链接,我看看是什么情况。
发表于 2023-4-8 22:12:58 | 显示全部楼层
回复 7# 思想之翼


   
从总字符串的一半(奇数则+1)开始递减,是否更快?

这种办法行不通,WADCBADCBA,WADCBADCBA,出现重复的子串在整个字符串中是重叠的。
你不能确定被截掉的另一半是否有重复的子串。
 楼主| 发表于 2023-4-8 22:40:39 | 显示全部楼层
本帖最后由 思想之翼 于 2023-4-8 22:57 编辑

回复 9# WHY

链接:https://pan.baidu.com/s/1Jw90mkqCSH1AzBsqvM_wfg?pwd=v5ak
提取码:v5ak

感谢帮助!您的代码这次测试是6.23秒,VBS代码测试是0.14秒
发表于 2023-4-9 01:13:49 | 显示全部楼层
回复 10# 思想之翼
  1. @if(0)==(0) echo off
  2. type a.txt | cscript //nologo //e:jscript "%~f0" > b.txt
  3. pause & exit
  4. @end

  5. var str = WSH.StdIn.ReadAll().replace(/\s/g, '');
  6. var Len = str.length;

  7. for (var i = Len-1; i > 0; i--) {
  8.     var key = str.substr(Len-i);
  9.     var arr = str.substr(0, Len-1).split(key);
  10.     if (arr.length > 1) {
  11.         for (var j = 0; j < Len-i; j++) {
  12.             if (str.substr(j, i) === key) {
  13.                 WSH.Echo(str.substr(i+j, 1));
  14.             }
  15.         }
  16.         break;
  17.     }
  18. }
复制代码

评分

参与人数 1技术 +1 收起 理由
思想之翼 + 1 感谢!耗时7毫秒

查看全部评分

发表于 2023-4-9 01:19:48 | 显示全部楼层
回复 10# 思想之翼


    这个VBS脚本不能用来解决这个问题,思路不一样。
如果字符串是:WADCBADCBAADCBA
应该提取红色的两个字符D和A,VBS只提取了一个A

评分

参与人数 1技术 +1 收起 理由
思想之翼 + 1 感谢

查看全部评分

发表于 2023-4-9 22:34:24 | 显示全部楼层
本帖最后由 WHY 于 2023-4-10 07:26 编辑

我贴一个vbs,0.03s 左右
  1. ST = Timer

  2. Dim srcFile, dstFile
  3. srcFile = "a.txt"
  4. dstFile = "b.txt"

  5. Dim fso, objFile
  6. Set fso = CreateObject("Scripting.FileSystemObject")
  7. Set objFile = fso.OpenTextFile(srcFile, 1)

  8. Dim strIn, strLine
  9. strIn = ""
  10. Do Until objFile.AtEndOfStream
  11.    strLine = objFile.ReadLine
  12.    If strLine <> "" Then strIn =  strLine & strIn
  13. Loop

  14. Dim reg
  15. Set reg = New RegExp
  16. reg.Global = True

  17. Dim strOut, i, key, match
  18. strOut = ""
  19. For i = Len(strIn)-1 To 1 Step -1
  20.     key = Left(strIn, i)
  21.     If InStr(2, strIn, key) > 0 Then
  22.         reg.Pattern = ".(?=" & key & ")"
  23.         For Each match In reg.Execute(strIn)
  24.             strOut = strOut & match & vbCrLf
  25.         Next
  26.         Exit For
  27.     End If
  28. Next

  29. fso.OpenTextFile(dstFile, 2, True).Write(strOut)

  30. MsgBox Timer - ST
复制代码

评分

参与人数 1技术 +1 收起 理由
思想之翼 + 1 感谢,值得学习

查看全部评分

 楼主| 发表于 2023-4-9 23:32:19 | 显示全部楼层
回复 11# WHY
虚心请教:下述表示路径出错,如何正确表述?
type a.txt | cscript //nologo //e:jscript "%~f0" > b.txt
type d:\测试1\a.txt | cscript //nologo //e:jscript "%~f0" > e:\测试2\b.txt
发表于 2023-4-10 00:15:59 | 显示全部楼层
回复 14# 思想之翼


    报错信息是什么?
D:\测试1\a.txt 和 E:\测试2 必须是真实存在的。脚本必须 ANSI 编码,UTF8 编码的话中文会出现乱码。

评分

参与人数 1技术 +1 收起 理由
思想之翼 + 1 感谢

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-18 22:34 , Processed in 0.023910 second(s), 9 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表