Delphi - 遍历字符串

5

我正在尝试找出字符串是否为“助记符类型”... 我的助记符类型由字母'a'到'z'和'A'到'Z',数字'0'到'9'以及额外的'_'组成。 我构建了以下代码。如果给定的字符串匹配我的助记符模式,则应该结果为True,否则为False:

 TRes := True;
 for I := 0 to (AString.Length - 1) do
 begin
     if not ((('0' <= AString[I]) and (AString[I] <= '9')) 
       or (('a' <= AString[I]) and (AString[I] <= 'z')) 
       or (('A' <= AString[I]) and (AString[I] <= 'Z')) 
       or (AString[I] = '_')) then
         TRes := False;
 end;

这段代码总是返回False。

2个回答

13

我假设您标记了问题XE5并使用了从零开始的索引,这意味着您的字符串是以零为基础的。但也许这个假设是错误的。

您的逻辑没问题,只是代码难以阅读。问题中的代码已经实现了您的意图,至少if语句确实执行了您想要的测试。

让我们重新编写您的代码,以使其更易于理解。我将以不同的方式排列它,并使用一个本地循环变量来表示每个字符:

for C in AString do
begin
  if not (
        (('0' <= C) and (C <= '9'))  // C is in range 0..9
     or (('a' <= C) and (C <= 'z'))  // C is in range a..z
     or (('A' <= C) and (C <= 'Z'))  // C is in range A..Z
     or (C = '_')                    // C is _
  ) then
    TRes := False;
end;

当这样写时,我相信你会同意它执行了你想要的测试。

但为了让代码更易懂,我会写一个IsValidIdentifierChar函数:

function IsValidIdentifierChar(C: Char): Boolean;
begin
  Result :=  ((C >= '0') and (C <= '9'))
          or ((C >= 'A') and (C <= 'Z'))
          or ((C >= 'a') and (C <= 'z'))
          or (C = '_');
end;

正如 @TLama 所说,你可以使用 CharInSet 更简洁地编写 IsValidIdentifierChar

function IsValidIdentifierChar(C: Char): Boolean;
begin
  Result := CharInSet(C, ['0'..'9', 'a'..'z', 'A'..'Z', '_']);
end;

然后您可以在此函数的基础上构建您的循环:

TRes := True;
for C in AString do
  if not IsValidIdentifierChar(C) do 
  begin
    TRes := False;
    break;
  end;

3
可以采用以下方式进行改写:使用 CharInSet(C, ['0'..'9', 'a'..'z', 'A'..'Z', '_']) 代替那种混乱的运算符组合。 - TLama
我错过了{$ZEROBASEDSTRINGS}。感谢其他的评论。 - Sebastian Xawery Wiśniowiecki
是的,我只是假设你在移动平台上。应该更加小心。在这里,for循环是你的朋友! - David Heffernan
嗨,我修复了问题,请检查一下是否可以获得一些“+”分数 :) - Sebastian Xawery Wiśniowiecki

7

字符串类型是从1开始计数的。动态数组是从0开始计数的。最好使用for ... in语句,这样您就可以确保在未来的Delphi版本中安全使用。

要测试可能字符值的范围,可以更高效地(并且更简洁地)使用CharInSet函数。

function IsMnemonic( AString: string ): Boolean;
var
  Ch: Char;
begin
  for Ch in AString do 
    if not CharInSet( Ch, [ '_', '0'..'9', 'A'..'Z', 'a'..'z' ] ) then 
      Exit( False );
  Result := True;
end;

1
字符串也可以是从零开始的,$ZEROBASEDSTRINGS ON - LU RD
这是XE5。我的假设是我们正在使用零基字符串。也许这是我太天真了。 - David Heffernan
@LU RD,这就是为什么for in是更好的解决方案。我认为XE5套件中并不是每个编译器都支持0/1选项(但可能是错误的)。 - Ritsaert Hornstra
2
也可以使用 for i := Low(AString) to High(AString) - LU RD
@LURD:仅在支持{$ZEROBASEDSTRINGS}的编译器版本中。 - Remy Lebeau
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接