【问题标题】:How to determine if all characters in a string are equal如何确定字符串中的所有字符是否相等
【发布时间】:2010-10-06 04:37:43
【问题描述】:

我需要知道字符串中的所有字符是否相等(由相同的字符组成)。该函数必须返回真或假,具体取决于字符串的所有元素是否等于特定字符。

我编写了这个运行良好的函数,但我正在寻找更优化(最快)的解决方案,字符串可以有数千个字符。

function AllElementsAreEqual(Element:Char;Str:String):Boolean;
var
  i : Integer;
begin
Result:=True;
 if Str<>'' then
  for i:=1 to Length(Str) do
   if  Str[i]<>Element then
   begin
      Result:= False;
      exit;
   end;
end;

更新 最后使用 Barry Kelly Suggestion 并添加inline 指令,性能明显提升。

function AllElementsAreEqual(Const Element:Char;Str:String):Boolean;inline;
type
ArrayInt = Array of Integer;
var
  i    : Integer;
  Delta: Integer;
  List : ArrayInt;
  Test : Integer;
begin
  Result:=True;
  Delta:=(Length(Str) mod  4);
  if Delta<>0 then
  Str:=Str+StringOfChar(Element,4-Delta);
  Test:=Ord(Element) + Ord(Element) shl 8 + Ord(Element) shl 16 + Ord(Element) shl 24;
  List:=ArrayInt(@(Str[1]));

  for i:=0 to ((Length(Str) div 4)-1) do
   if List[i]<>Test  then
    begin
     Result:=False;
     exit;
    end;
end;

更新 2

很抱歉,我发布了解决方案的旧实现(带有错误),现在已修复。 感谢 The_Fox 为 Barry 建议创建更好的实现。

【问题讨论】:

  • 为什么不使用“===”三元组,这就是它的用途。比较是否绝对 = to。检查数据类型以及字符
  • @Val,Delphi 什么时候有“===”?您是否将 Delphi 与 JavaScript 混淆了?
  • 糟糕,我在想别的东西……

标签: delphi string delphi-7


【解决方案1】:

您可以考虑创建一个 Integer 值,其中 Element 重复 4 次(因为这是在 Delphi 7 中的 AnsiChar),像 Ord(Element) + Ord(Element) shl 8 + Ord(Element) shl 16 + Ord(Element) shl 24 一样移动,然后将字符串类型转换为 PIntegerArray (@987654326 @) 并循环它Length(Str) div 4 次,比较为整数而不是字符。不过,您需要手动比较最后几个 Length(str) mod 4 字符。

【讨论】:

  • 这就是Delphi编译器用来这么快的技巧吗? ;)
  • 这是它用于字符串散列和比较的技巧之一,是的。
【解决方案2】:

您错误地执行了 Barry Kelly 的建议。当我在 Delphi 7 上测试它时,它甚至比你的第一个实现还要慢,如果你的字符串长度不能被 4 整除,它会给出错误的结果。

我用这个字符串测试了它:StringOfChar('c', 100000) + 'x';,你的新函数返回 True AllElementsAreEqual('c', StringOfChar('c', 100000) + 'x'),而它应该返回 False。

您的实现速度较慢,因为您试图使您的字符串可被 4 整除(其中您失败了,但您可以自己找出失败的原因),因此创建了一个需要内存分配的新字符串,这是昂贵的。

你做的另一件危险的事情是让一个动态数组(整数数组)指向一个字符串。两者都被引用,这可能会导致奇怪的结果。请听从 Barry Kelly 的建议并使用 PIntegerArray!

我认为巴里·凯利的意思是:

function AllElementsAreEqual(const aElement: Char; const aStr: string): Boolean;
var
  lIntArray: PIntegerArray;
  i: Integer;
  lTest: Integer;
begin
  Result := True;
  lTest := Ord(aElement) + Ord(aElement) shl 8 + Ord(aElement) shl 16 + Ord(aElement) shl 24;

  lIntArray := @aStr[1];
  for i := 0 to Length(aStr) div 4 - 1 do
    if lIntArray[i] <> lTest then
    begin
      Result := False;
      Exit;
    end;

  for i := Length(aStr) - (Length(aStr) mod 4) + 1 to Length(aStr) do
    if aStr[i] <> aElement then
    begin
      Result := False;
      Exit;
    end;
end;

注意:您的函数对空字符串返回 True,可以吗?

NB2:请给 Barry Kelly 的回答而不是我的回答加分,因为这确实是一个过分的评论而不是回答。

【讨论】:

  • +1 很抱歉,但昨晚我用不同的实现做了很多测试,我发布了提议的解决方案的旧实现(有一个错误),现在已修复。非常感谢您更好地实施 Barry 的建议。
【解决方案3】:

也许使用StringOfChar 生成一个目标字符重复N次的字符串,然后进行字符串比较而不是逐个字符比较。

(不知道这是否真的更快;测量并查看)。

【讨论】:

    【解决方案4】:

    您可以实现Select algorithm 以更快地找到不合适的字符,这不会提高字符串为“True”的速度,但它应该会使其更快一些。

    【讨论】:

      【解决方案5】:

      获取字符串长度,使用GetMem分配字符串大小的内存。用所需的字符填充内存。然后使用 CompareMem 比较字符串和内存

      【讨论】:

        【解决方案6】:

        根据我从您的代码中了解到的情况

        Result:= False;
        

        ":=" 用于为变量赋值。你如何比较delphi中的2个值?

        【讨论】:

        • 在逻辑上,用等号,而不是等于或===或其他奇怪的东西。 := 通常读作“分配给”或“成为”。 == 来自“C”(最初是“B”)。但是 BCPL 使用了 :=,它来自 Algol。由于这个奇怪的决定(可能是由 Thompson 和/或 Ritchie 做出的),数以千计的错误是由于误用 = 而不是 ==
        • 天才,我怎么可能从来没想过。坦率地说,我从未见过如此出色的答案,但您错过了一些东西,即: 标记在英语中称为冒号。我希望这里有很多人继续投票支持你的答案。 >-(
        • 讽刺是没有必要的,@Vantomex。
        • @Rob,你没看到他只是想故意玩弄他的答案吗?如果没有这样做的后果,这种不良态度可能会一次又一次地重复。你为什么对我这么说,格里也和我一样?你为什么不绝对警告@KhanZeeshan?
        猜你喜欢
        • 2013-04-08
        • 2017-08-12
        • 2012-04-11
        • 2019-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多