【问题标题】:Best way to check if a character is contained in an array of char检查字符是否包含在 char 数组中的最佳方法
【发布时间】:2016-02-23 20:16:29
【问题描述】:

我知道,我会写

if C in ['#', ';'] then ...

如果CAnsiChar

但是这个

function CheckValid(C: Char; const Invalid: array of Char; OtherParams: TMyParams): Boolean;
begin
    Result := C in Invalid;    // <-- Error because Invalid is an array not a set
    //maybe other tests...
    //Result := Result and OtherTestsOn(OtherParams);
end;

产生E2015: Operator not applicable to this operand type

有没有一种简单的方法可以检查字符是否包含在字符数组中(除了遍历数组)?

【问题讨论】:

  • ['#', ':']char 集,而不是 char 数组,对于 Unicode 版本的 Delphi (2009+ ),请改用CharInSet,但请查看stackoverflow.com/questions/4237339/…中的注意事项
  • @GerryColl 你是对的,我相应地纠正了这个问题。谢谢你的提示。我的代码只是一个例子。但在这种特殊情况下,我担心array of char
  • 您不能将in 运算符用于数组,只能用于集合。
  • 澄清:CheckValid() 并不意味着尝试编写 IsCharInArray() 函数,而应仅作为用例的示例。

标签: delphi delphi-xe4


【解决方案1】:

我知道您不想这样做,但出于性能原因,这是迭代数组确实是最佳选择的情况之一:

function CheckValid(C: Char; const Invalid: array of Char): Boolean;
var
  I: Integer;
begin
  Result := False;
  for I := Low(Invalid) to High(Invalid) do begin
    if Invalid[I] = C then begin
      Result = True;
      Exit;
    end;
  end;
end;

或者:

function CheckValid(C: Char; const Invalid: array of Char): Boolean;
var
  Ch: Char;
begin
  Result := False;
  for Ch in Invalid do begin
    if Ch = C then begin
      Result = True;
      Exit;
    end;
  end;
end;

将输入数据转换为字符串只是为了搜索它可能会导致巨大的性能瓶颈,特别是如果函数被频繁调用,例如在循环中。

【讨论】:

  • 如果数组Invalid包含CCheckValid()不应该返回False吗?或者,您可以将函数重命名为更通用的名称,例如IsCharInArray().
  • @RenéHoffmann:这取决于函数的使用方式。如果 C 应该在数组中,它可能返回 True,否则返回非法。或者如果 C 不应该在数组中,则它可能返回 False,如果它是,则它是非法的。
  • 因此,函数名称的用途不明确。
  • @RenéHoffmann 我的问题不是关于如何编写函数IsCharInArray(),而是关于如何在我不愿意定义这样的函数的情况下快速检查一个字符是否在数组中。因此我最初选择了这个名字。
  • @RemyLebeau 我同意 René 的观点,即命名和返回值令人困惑。我也建议在IsCharInArray()中重命名CheckValid()
【解决方案2】:

如果有人试图避免遍历数组并且如果速度无关紧要,那么IndexOfAny 可能会有所帮助:

function CheckValid(C: Char; const Invalid: array of Char; OtherParams: TMyParams): Boolean;
begin
    Result := string(C).IndexOfAny(Invalid) >= 0;
    //maybe other test...
    //....
end;

来自 Delphi 文档:

[IndexOfAny r] 返回一个整数,指示在从 0 开始的字符串中找到的第一个给定字符的位置。 [如果找不到字符,则返回-1。]

如果担心速度,应该避免这种情况,正如 @RemyLebeau 在 cmets 中解释的那样:

将 C 转换为字符串以调用 IndexOfAny() 将创建 1 个临时字符串。 [...] 如果经常调用 CheckValid(),那么这些转换可能是一个很大的性能瓶颈,更不用说浪费内存了。

在这种情况下,@RemyLebeau 的答案是更好的解决方案。

【讨论】:

  • 试试Pos(C, Invalid) &gt; 0
  • @Abelisto 这似乎也有效。为什么?字符数组是否自动转换为字符串?
  • 是的,char 数组隐式转换为字符串。
  • CInvalid 传递给Pos() 将创建2 个临时Strings。将C 转换为String 以调用IndexOfAny() 将创建1 个临时String。无论哪种方式,如果经常调用CheckValid(),这些转换可能会成为BIG 性能瓶颈,更不用说浪费内存了。您最好直接遍历数组,寻找与C 值匹配的元素。不会进行任何转换,代码会执行得更快。
  • @RemyLebeau 我很欣赏您的评论并接受了您的答案。无论如何,我都会留下修改后的答案,因为我认为有时为此使用单行代码会很有用。我希望我在回答中引用了您的评论是可以的。
猜你喜欢
  • 2011-07-04
  • 2010-12-20
  • 1970-01-01
  • 2016-07-02
  • 2014-12-20
  • 2012-06-15
  • 2011-06-04
  • 2013-06-25
  • 1970-01-01
相关资源
最近更新 更多