针对常量整数集的案例陈述?

Case statement against constant set of integers?

精简版

给定:

    const
       Whitespace = [[=10=]09, [=10=]0A, [=10=]0C, [=10=]20];

长版

通常,如果您要有一个 case 语句,您可以为每种情况包含不同的值,例如:

var
  ch: UCS4Char; // unsigned 32-bit

case ch of
48..57: {asciiDigit}; //i.e. '0'..'9'
65..70: {asciiUpperHexDigit}; //i.e. 'A'..'F'
97..102: {asciiLowerHexDigit}; //i.e. 'a'..'f'
end;

可行,但我希望这些值是常量:

const
  //https://infra.spec.whatwg.org/#code-points
  asciiDigit         = [Ord('0')..Ord('9')]; //https://infra.spec.whatwg.org/#ascii-digit
  asciiUpperHexDigit = [Ord('A')..Ord('F')]; //https://infra.spec.whatwg.org/#ascii-upper-hex-digit
  asciiLowerHexDigit = [Ord('a')..Ord('f')]; //https://infra.spec.whatwg.org/#ascii-lower-hex-digit
  asciiHexDigit      = asciiUpperHexDigit + asciiLowerHexDigit; //https://infra.spec.whatwg.org/#ascii-hex-digit
  asciiUpperAlpha    = [Ord('A')..Ord('Z')]; //https://infra.spec.whatwg.org/#ascii-upper-alpha
  asciiLowerAlpha    = [Ord('a')..Ord('z')]; //https://infra.spec.whatwg.org/#ascii-lower-alpha
  asciiAlpha         = asciiUpperAlpha + asciiLowerAlpha; //https://infra.spec.whatwg.org/#ascii-alpha
  asciiAlphaNumeric  = asciiDigit + asciiAlpha; //https://infra.spec.whatwg.org/#ascii-alphanumeric

是否有 any 排列的 any 语法允许:

或者我是否永远坚持以下内容?

var
  ch: UCS4Char; //unsigned 32-bit

case ch of
Ord('!'): FState := MarkupDeclarationOpenState;
Ord('/'): FState := EndTagOpenState;
Ord('?'): AddParseError('unexpected-question-mark-instead-of-tag-name');
UEOF: AddParseError('eof-before-tag-name parse error');
Whitespace: FState := SharkTankContosoGrobber;
else
  if ch in asciiDigit then
  begin
    FReconsume := True;
    FState := tsTagNameState;
  end
  else
    AddParseError('invalid-first-character-of-tag-name parse error');
end;

显然,使用概念 case 与正在执行的逻辑匹配;必须做的 if-elseif 是......较少。

注意:我不需要它实际上成为Delphi "set",即具有特定含义的特定术语。我只想:

case ch of Whitespace: ...

以同样的方式工作:

if ch in Whitespace then...

已经有效了。

而且我们知道编译器已经可以将 Cardinal 与“集合”进行比较,因为以下已经有效:

case ch of
[=16=]0A, [=16=]0D, [=16=]09, [=16=]32: ...
end;

它将 Cardinal 与“一组数字”进行比较。

红利阅读

不,不支持。

根据官方documentation

A case statement has the form:

case selectorExpression of
  caseList1: statement1;
   ...
  caseListn: statementn;
end

where [...] each caseList is one of the following:

  • A numeral, declared constant, or other expression that the compiler can evaluate without executing your program. It must be of an ordinal type compatible with selectorExpression. [...]
  • A subrange having the form First..Last, where First and Last both satisfy the criterion above and First is less than or equal to Last.
  • A list having the form item1, ..., itemn, where each item satisfies one of the criteria above.

因此,作为 case 语法的一部分,这仅允许单个值、显式范围和此类值的列表。

尽管 Delphi 文档很好,但它并不完美,您不能 100% 依赖它。但是,我相信所有有经验的 Delphi 开发人员都会同意 caseList 不能是预先声明的 single-identifier 与 selectorExpression.[=29= 兼容的序数值的“集合” ]

您可以在 Embarcadero's Jira 提交功能请求。


但是您可以使用范围语法和先前声明的子范围类型(不是设置常量)来实现部分类似的东西:

type
  TAsciiDigit = '0'..'9';
  TAsciiLatinCapitalLetter = 'A'..'Z';
  TAsciiLatinSmallLetter = 'a'..'z';

procedure TForm1.FormCreate(Sender: TObject);
begin

  var c := 'R';

  case c of
    Low(TAsciiDigit) .. High(TAsciiDigit):
      ShowMessage('Digit!');
    Low(TAsciiLatinCapitalLetter) .. High(TAsciiLatinCapitalLetter):
      ShowMessage('Capital!');
    Low(TAsciiLatinSmallLetter) .. High(TAsciiLatinSmallLetter):
      ShowMessage('Small letter!');
  else
    ShowMessage('Something else.');
  end;

end;

加分项: 事实上,文档的非 100% 准确性可以在上面引用的部分中看到:

selectorExpression is any expression of an ordinal type smaller than 32 bits

那是胡说八道。 selectorExpression当然可以是32位整数。