不区分大小写的Pos

sma*_*ins 11 delphi delphi-2010

在D2010(unicode)中是否有类似Pos的类似功能不区分大小写?

我知道我可以使用Pos(AnsiUpperCase(FindString),AnsiUpperCase(SourceString))但是每次调用函数时都会通过将字符串转换为大写来增加处理时间.

例如,在1000000循环上,Pos需要78ms而转换为大写需要764ms.

str1 := 'dfkfkL%&/s"#<.676505';
  for i := 0 to 1000000 do
    PosEx('#<.', str1, 1); // Takes 78ms

  for i := 0 to 1000000 do
    PosEx(AnsiUpperCase('#<.'), AnsiUpperCase(str1), 1); // Takes 764ms
Run Code Online (Sandbox Code Playgroud)

我知道为了提高这个特定示例的性能,我可以在循环之前将字符串首先转换为大写,但我之所以想要具有不区分大小写的Pos函数的原因是从FastStrings中替换一个.我将使用Pos的所有字符串都将不同,因此我需要将每个字符串转换为大写字母.

是否有任何其他功能可能比Pos +将字符串转换为大写更快?

Jer*_*ers 24

内置的德尔福函数来做到这一点是在两个AnsiStrings.ContainsText为AnsiStrings和StrUtils.ContainsText为Unicode字符串.

然而,在后台,它们使用的逻辑与您的逻辑非常相似.

无论在哪个库中,这样的函数总是很慢:特别是为了与Unicode兼容,它们需要有相当多的开销.由于它们位于循环内部,因此成本很高.

避免开销的唯一方法是尽可能地在循环外进行这些转换.

所以:按照你自己的建议,你有一个非常好的解决方案.

--jeroen

  • -1:AnsiStrings.ContainsText不返回子字符串的位置,只返回字符串中是否存在子字符串. (6认同)
  • Steve,在我的版本中,`ContainsText`函数是通过改变两个输入参数的大小写,调用`Pos`,然后检查结果大于零来实现的.返回结果而不是检查它是否为正,并且您有一个不区分大小写的`Pos`. (5认同)
  • 对不起 - 我误读了原帖,因为只有它包含了这个位置才感兴趣.无论如何,ContainsText足以说明Delphi团队如何解决这个问题,因此我的消息中的结论仍然存在. (2认同)

GJ.*_*GJ. 9

这个版本的我之前的答案适用于D2007和D2010.

  • 在Delphi 2007中,它CharUpCaseTable是256字节
  • 在Delphi 2010中,它是128 KB(65535*2).

原因是Char大小.在旧版本的Delphi中,我的原始代码仅支持初始化时的当前语言环境字符集.我的InsensPosEx速度比你的代码快4倍.当然有可能走得更快,但我们会失去简单性.

type
  TCharUpCaseTable = array [Char] of Char;

var
  CharUpCaseTable: TCharUpCaseTable;

procedure InitCharUpCaseTable(var Table: TCharUpCaseTable);
var
  n: cardinal;
begin
  for n := 0 to Length(Table) - 1 do
    Table[Char(n)] := Char(n);
  CharUpperBuff(@Table, Length(Table));
end;

function InsensPosEx(const SubStr, S: string; Offset: Integer = 1): Integer;
var
  n:            Integer;
  SubStrLength: Integer;
  SLength:      Integer;
label
  Fail;
begin
  Result := 0;
  if S = '' then Exit;
  if Offset <= 0 then Exit;

  SubStrLength := Length(SubStr);
  SLength := Length(s);

  if SubStrLength > SLength then Exit;

  Result := Offset;
  while SubStrLength <= (SLength-Result+1) do 
  begin
    for n := 1 to SubStrLength do
      if CharUpCaseTable[SubStr[n]] <> CharUpCaseTable[s[Result+n-1]] then
        goto Fail;
      Exit;
Fail:
    Inc(Result);
  end;
  Result := 0;
end;

//...

initialization
  InitCharUpCaseTable({var}CharUpCaseTable);
Run Code Online (Sandbox Code Playgroud)


fro*_*ogb 5

我还遇到了转换FastStrings的问题,它使用Boyer-Moore(BM)搜索来获得D2009和D2010的速度.由于我的许多搜索仅查找单个字符,并且其中大多数都在寻找非字母字符,因此我的D2010版本的SmartPos具有一个带有widechar作为第一个参数的重载版本,并且通过字符串进行简单的循环找到这些.我使用两个参数的大写来处理少数不区分大小写的情况.对于我的应用程序,我相信这个解决方案的速度可与FastStrings相媲美.

对于'字符串查找'的情况,我的第一个传递是使用SearchBuf并执行大写并接受惩罚,但我最近一直在研究使用Unicode BM实现的可能性.您可能知道,BM不能很好地扩展到Unicode比例的字符集,但在Soft Gems中有一个Unicode BM实现.这个在D2009和D2010之前,但看起来好像很容易转换.作者Mike Lischke通过包含一个67kb的Unicode大写表解决了大写问题,这对于我的适度要求来说可能是一个太过分了.由于我的搜索字符串通常较短(尽管不像单个三字符示例那么短),因此Unicode BM的开销也可能是不值得付出的代价:BM优势随着搜索字符串的长度而增加.

这肯定是在将Unicode BM合并到我自己的应用程序之前需要使用一些真实的特定于应用程序的示例进行基准测试的情况.

编辑:一些基本的基准测试表明我对"Unicode Tuned Boyer-Moore"解决方案保持警惕是正确的.在我的环境中,UTBM会产生更大的代码,更长的时间.如果我需要这个实现提供的一些额外功能(处理代理和全字搜索),我可能会考虑使用它.