我已经制作了一个纯粹的Pascal函数来查找Unicode字符串中字符的位置,如下所示:
function CharPosEx(const chChr: Char; const sStr: string;
const iOffset: Integer=1): Integer;
var
PStr : PChar;
PRunIdx: PChar;
PEndIdx: PChar;
iLenStr: Integer;
begin
Result := 0;
iLenStr := Length(sStr);
if (iLenStr = 0) or (iOffset <= 0) or (iOffset > iLenStr) then Exit;
PStr := Pointer(sStr);
PEndIdx := @PStr[iLenStr - 1];
PRunIdx := @PStr[iOffset - 1];
repeat
if PRunIdx^ = chChr then begin
Result := PRunIdx - PStr + 1;
Exit;
end;
Inc(PRunIdx);
until PRunIdx > PEndIdx;
end;
我决定不使用内置StrUtils.PosEx()
,因为我想基于UTF16_CharPosEx
的优化纯Pascal函数创建CharPosEx
函数。我正试图找到一个更快的通用解决方案,如Fastcode Project的纯粹Pascal方法。
根据问题的接受答案 Delphi: fast Pos with 64-bit ,找到字符串中子字符串位置的最快的纯Pascal函数是PosEx_Sha_Pas_2()
CharPos()
3}}
对于最快的纯Pascal函数来查找字符串中字符的位置,我注意到Fastcode Project有CharPosIEx()
,CharPosEY()
和CharPosRev()
表示从左到右匹配,以及从右到左匹配的CharPos()
。
然而,问题是所有Fastcode函数都是在Delphi 2009之前开发的,Delphi 2009是第一个支持Unicode的Delphi版本。
我对CharPosEY()
和CharPos
感兴趣。我想重新对它们进行基准测试,因为现在有一些无用的优化技术,例如偶尔在Fastcode函数中实现的循环展开技术。
但是,我不能为每个CharPos()
家庭挑战重新编译基准测试项目,因为我一直在使用Delphi XE3,因此我不能断定哪一个是最快的。
这里的任何人都知道或可以推断哪一个是针对每个提到的Fastcode挑战最快的纯Pascal实现,特别是对于CharPosEY()
和UnicodeString
?
欢迎Fastcode Project解决方案中的其他方法。
plot(x = seq(size), means, pch = 20, **ylim=c(?,?)**, ylab="Mean", main="Analysis of Means", xaxt = 'n')
axis(1,seq(size))
segments(seq(size), u, seq(size), means)
lines(seq(1, 15, 1), rep(u_vec + seg, each = 1), type = "S")
lines(seq(1, 15, 1), rep(u_vec - seg, each = 1), type = "S")
abline(h=u)
,无论其编码方案如何。答案 0 :(得分:3)
在快速代码示例中查找字符串中的字符的许多解决方案使用一种技术将较大块中的字符串读入寄存器,然后分析寄存器字节以进行匹配。当字符是单字节时,这可以正常工作,但当字符是16位unicode时,它不是最佳的。
有些示例甚至使用查找表,但在unicode字符串搜索中也不是最佳选择。
我发现fastcode purepascal PosEx_Sha_Pas_2
字符串搜索例程在32/64位模式下工作得非常好,即使对于单字符搜索也是如此。
你也可以使用那个例程。
我将PosEx_Sha_Pas_2
中不需要的部分删除到CharPosEx_LU_Pas中,并获得了一定的执行时间百分比:
function CharPosEx_LU_Pas(c: Char; const S: string; Offset: Integer = 1): Integer;
var
len: Integer;
p, pStart, pStop: PChar;
label
Loop0, Loop4,
TestT, Test0, Test1, Test2, Test3, Test4,
AfterTestT, AfterTest0,
Ret;
begin;
p := Pointer(S);
if (p = nil) or (Offset < 1) then
begin;
Exit(0);
end;
len := PLongInt(PByte(p) - 4)^; // <- Modified to fit 32/64 bit
if (len < Offset) then
begin;
Exit(0);
end;
pStop := p + len;
pStart := p;
p := p + Offset + 3;
if p < pStop then
goto Loop4;
p := p - 4;
goto Loop0;
Loop4:
if c = p[-4] then
goto Test4;
if c = p[-3] then
goto Test3;
if c = p[-2] then
goto Test2;
if c = p[-1] then
goto Test1;
Loop0:
if c = p[0] then
goto Test0;
AfterTest0:
if c = p[1] then
goto TestT;
AfterTestT:
p := p + 6;
if p < pStop then
goto Loop4;
p := p - 4;
if p < pStop then
goto Loop0;
Exit(0);
Test3:
p := p - 2;
Test1:
p := p - 2;
TestT:
p := p + 2;
if p <= pStop then
goto Ret;
Exit(0);
Test4:
p := p - 2;
Test2:
p := p - 2;
Test0:
Inc(p);
Ret:
Result := p - pStart;
end;
我声称此代码段没有原创性,因为从PosEx_Sha_Pas_2中删除不需要的代码部分是一项简单的任务。
基准32位(101个字符串,最后一个字符匹配): 重复50000000次。
System.Pos: 1547 ms
PosEX_Sha_Pas_2: 1292 ms
CharPosEx: 2315 ms
CharPosEx_LU_Pas: 1103 ms
SysUtils.StrScan: 2666 ms
基准64位(101个字符串,最后一个字符匹配): 重复50000000次。
System.Pos: 20928 ms
PosEX_Sha_Pas_2: 1783 ms
CharPosEx: 2874 ms
CharPosEx_LU_Pas: 1728 ms
SysUtils.StrScan: 3115 ms