实现了对超长字符串的大小写不敏感比较,并通过不同的方法对性能进行了比较测试,包括使用系统 API、机器码和纯 AHK 遍历的方法。
#MaxMem 4095 SetBatchLines -1 ; 比较字符串不区分大小写(并获得不同的基于 1 的字符索引) vText1 := StrReplace(Format("{:241001000}", ""), " ", "a") ; MsgBox % vText1 ; 生成241001000个字符串a vText2 := vText1 vText1 .= "A" vText2 .= "b" ;vText2 .= "a" ; https://www.autohotkey.com/boards/viewtopic.php?p=297807#p297807 计时() vRet := StrCmpI(vText1, vText2,, vOffsetDiff) MsgBox, , 调用WinAPI的RtlCompareMemory比较, % "耗时:" 计时() "ms`n发现差异的字符位置:" vOffsetDiff "`n返回值:" vRet ; C语言机器码纯遍历,缺少分块优化 计时() MyFunction := MCode("1,x64:33C04C8BC94D85C07E1E4C2BCA0F1F000FB70A48FFC06641390C11750B4883C202493BC07CEA33C0C3") MsgBox, , 机器码c纯遍历, % "发现差异的字符位置:" DllCall(MyFunction, "Str", vText1, "Str", vText2, "int64", 241001000+1, "int64") "`n耗时:" 计时() "ms" ; 此项仅为了对比效率差异 计时() vOffsetDiff := qSortErrorLookup(vText1, vText2) MsgBox, , ahk纯Loop遍历检测, % "耗时:" 计时() "ms`n发现差异的字符位置:" vOffsetDiff return 计时() { Static if 开始= DllCall("QueryPerformanceFrequency", "Int64*", 频率), DllCall("QueryPerformanceCounter", "Int64*", 开始) else DllCall("QueryPerformanceCounter", "Int64*", 结束), 耗时:=(结束 - 开始)/频率*1000, 开始:="" Return 耗时 } ;principles: ;use _wcsnicmp/_strnicmp to compare blocks of characters, find the first difference ;use memmove to copy blocks ;use CharLowerBuff to make them lower case ;use RtlCompareMemory to compare characters, find the first difference (its char index) ;note: vOffsetParam is for use with comparator functions for AHK's Sort command ;note: vText1/vText2 are ByRef for better performance (to avoid copying massive strings) StrCmpI(ByRef vText1, ByRef vText2, vOffsetParam:=0, ByRef vOffsetOut:=0) { local static vChrSize := A_IsUnicode ? 2 : 1 static vFunc := A_IsUnicode ? "msvcrt\_wcsnicmp" : "msvcrt\_strnicmp" static vBlockLen := 1000000 vLen1 := StrLen(vText1) , vLen2 := StrLen(vText2) if !(vLen := Min(vLen1, vLen2)) return -vOffsetParam ;return 0/-vOffsetParam if both empty strings vRem := Mod(vLen, vBlockLen) , vOffset := vOffsetOut := vRet := 0 Loop % Floor(vLen/vBlockLen) { if vRet := DllCall(vFunc, "Ptr",&vText1+vOffset*vChrSize, "Ptr",&vText2+vOffset*vChrSize, "Ptr",vBlockLen, "Cdecl") break vOffset += vBlockLen } if !vRet && (vBlockLen := vRem) vRet := DllCall(vFunc, "Ptr",&vText1+vOffset*vChrSize, "Ptr",&vText2+vOffset*vChrSize, "Ptr",vRem, "Cdecl") if !vRet { if (vLen1 = vLen2) return -vOffsetParam ;return 0/-vOffsetParam if equal vOffsetOut := vLen + 1 return (vLen1 > vLen2) ? 1 : -1 } VarSetCapacity(vTemp1, vBlockLen*vChrSize) , VarSetCapacity(vTemp2, vBlockLen*vChrSize) , DllCall("msvcrt\memmove", "Ptr",&vTemp1, "Ptr",&vText1+vOffset*vChrSize, "UPtr",vBlockLen*vChrSize, "Cdecl Ptr") , DllCall("msvcrt\memmove", "Ptr",&vTemp2, "Ptr",&vText2+vOffset*vChrSize, "UPtr",vBlockLen*vChrSize, "Cdecl Ptr") , DllCall("user32\CharLowerBuff", "Ptr",&vTemp1, "UInt",vBlockLen, "UInt") , DllCall("user32\CharLowerBuff", "Ptr",&vTemp2, "UInt",vBlockLen, "UInt") , vOffset2 := DllCall("ntdll\RtlCompareMemory", "Ptr",&vTemp1, "Ptr",&vTemp2, "UPtr",vBlockLen*vChrSize, "UPtr") ;note: use Floor, since, for a Unicode string, the first byte that differs could be at an odd offset: , vOffsetOut := vOffset + Floor(vOffset2/vChrSize) + 1 return (vRet > 0) ? 1 : -1 } ; ahk纯遍历检测函数 qSortErrorLookup(byref string1, byref string2, partCount := 2) { Local if (string1 = string2) Return false cLeftBorder := 1 , cLen := Max(StrLen(string1), StrLen(string2)) Loop { stepSize := (cLen)/partCount , leftBorder := cLeftBorder Loop %partCount% { leftB := Round(leftBorder) , len := Round((leftBorder+=stepSize)-leftB) if (SubStr(string1, leftB, len) != SubStr(string2, leftB, len)) { if (len = 1) Return leftB cLeftBorder := leftB , cLen := len Break } } } Return false } MCode(mcode) { static e := {1:4, 2:1}, c := (A_PtrSize=8) ? "x64" : "x86" if (!regexmatch(mcode, "^([0-9]+),(" c ":|.*?," c ":)([^,]+)", m)) return if (!DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", 0, "uint*", s, "ptr", 0, "ptr", 0)) return p := DllCall("GlobalAlloc", "uint", 0, "ptr", s, "ptr") if (c="x64") DllCall("VirtualProtect", "ptr", p, "ptr", s, "uint", 0x40, "uint*", op) if (DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", p, "uint*", s, "ptr", 0, "ptr", 0)) return p DllCall("GlobalFree", "ptr", p) }
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。
评论(0)