如何清洗/验证字符串以将其分配给组件名称?

时间:2009-10-22 07:42:13

标签: delphi

我有一个列出部门的子菜单。在这个背后,每个部门都有一个名为“actPlan”+ department.name。

的行动

现在我意识到这是一个坏主意,因为名称可以包含世界上任何奇怪的字符,但action.name不能包含国际字符。显然Delphi IDE本身调用一些方法来验证字符串是否是有效的组件名。谁知道更多关于这个?

我还有一个使用

的想法
Action.name := 'actPlan' + department.departmentID;

代替。优点是departmentID是一种已知格式,'xxxxx-x'(其中x是1-9),所以我只需要用例如下划线替换' - '。这里的问题是那些旧的动作名已经存在于个人文本文件中。如果我突然从使用部门名称更改为ID,那将是例外。

我当然可以第一次吃异常,然后调用一个搜索方法,用正确的数据替换该文本文件并重新加载它。

所以基本上我搜索最优雅和未来的方法来解决这个问题:) 我用的是D2007。

3 个答案:

答案 0 :(得分:10)

使用 SysUtils 中的IsValidIdent函数验证组件名称,该函数只检查第一个字符是字母还是下划线以及所有后续字符是字母数字还是下划线。

要创建符合这些规则的字符串,只需删除任何不符合条件的字符,然后在结果以数字开头时添加符合条件的字符。

对于相似的名称,该转换可能会产生相同的结果。如果这不是您想要的,那么您可以在字符串末尾添加唯一的内容,例如根据输入字符串或部门ID计算的校验和。

function MakeValidIdent(const s: string): string;
var
  len: Integer;
  x: Integer;
  c: Char;
begin
  SetLength(Result, Length(s));
  x := 0;
  for c in s do
    if c in ['A'..'Z', 'a'..'z', '0'..'9', '_'] then begin
      Inc(x);
      Result[x] := c;
    end;
  SetLength(Result, x);
  if x = 0 then
    Result := '_'
  else if Result[1] in ['0'..'9'] then
    Result := '_' + Result;
  // Optional uniqueness protection follows. Choose one.
  Result := Result + IntToStr(Checksum(s));
  Result := Result + GetDepartment(s).ID;
end;

在Delphi 2009及更高版本中,使用CharInSet函数调用替换后两个in运算符。 (Unicode字符不适用于Delphi集。)在Delphi 8及更早版本中,将第一个in运算符更改为经典for循环并将索引更改为s

答案 1 :(得分:5)

我写了一个例程

// See SysUtils.IsValidIdent:
function MakeValidIdent(const AText: string): string;
const
  Alpha = ['A'..'Z', 'a'..'z', '_'];
  AlphaNumeric = Alpha + ['0'..'9'];

  function IsValidChar(AIndex: Integer; AChar: Char): Boolean;
  begin
    if AIndex = 1 then
      Result := AChar in Alpha
    else
      Result := AChar in AlphaNumeric;
  end;

var
  i: Integer;
begin
  Result := AText;
  for i := 1 to Length(Result) do
    if not IsValidChar(i, Result[i]) then
      Result[i] := '_';
end;

从字符串生成Pascal标识符。 您可能还想从Classes.pas复制FindUniqueName并将其应用于MakeValidIdent的结果。

答案 2 :(得分:0)

这是我的惯例:

function MakeValidIdent(const s: string): string;
begin
  Result := 'clm'; //Prefix
  for var c in s do
    if CharInSet(c, ['A'..'Z', 'a'..'z', '0'..'9', '_']) then
      Result := Result + c;
end;