实现了对超长字符串的大小写不敏感比较,并通过不同的方法对性能进行了比较测试,包括使用系统 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)