【问题标题】:Defining a string type to be a certain format将字符串类型定义为某种格式
【发布时间】:2011-12-05 21:11:29
【问题描述】:

我想知道是否有一种方法可以在 delphi 7 中定义一种字符串类型或类似的类型,旨在采用特定格式或匹配某些规范?例如,我想定义一个TSizeString 类型,它接受诸如4x69x12 甚至2.5x10.75 之类的值。它应该要求 x 作为两个数字之间的唯一分隔符。所以不应该有像x9652-44-6x6-2 甚至4 x 6 这样的东西。

只需INTEGER + 'x' + INTEGERSINGLE + 'x' + SINGLE

我猜想与 TFilename 的工作方式类似,标准文件名可能看起来像 C:\MyPath\MyFile.txt\\Storage\SomeDir\SomeFile.doc

【问题讨论】:

  • TFilename 没有什么神奇之处。它被简单地定义为type TFileName = type string。您可以将数学公式或莎士比亚小说分配给TFileName 类型的变量。
  • 无论如何,这可以通过高级记录和运算符重载来实现。我已经写了样本aboutthat。不过,我不记得 Delphi 7 是否支持高级记录/运算符重载。
  • 正如我在下面的评论中提到的,我可以使用具有AsString 属性的类作为该类的默认值吗?我的意思是,如果我将类的字符串属性发布为类的Default,我可以像字符串一样读取/写入该类吗?
  • 或者这仅适用于使用索引属性?
  • 默认属性必须被索引。

标签: string delphi casting delphi-7


【解决方案1】:

在较新版本的 Delphi 中,高级记录和运算符重载在这种情况下非常方便:

type
  TSizeString = record
    x, y: single;
  public
    class operator Implicit(const S: string): TSizeString;
    class operator Implicit(const S: TSizeString): string;
  end;

implementation

class operator TSizeString.Implicit(const S: string): TSizeString;
var
  DelimPos: integer;
begin
  DelimPos := Pos('x', S);
  if (DelimPos = 0) or (not TryStrToFloat(Copy(S, 1, DelimPos-1), result.X)) or
    (not TryStrToFloat(Copy(S, DelimPos + 1), result.y)) then
    raise Exception.CreateFmt('Invalid format of size string "%s".', [S]);
end;

class operator TSizeString.Implicit(const S: TSizeString): string;
begin
  result := FloatToStr(S.x) + 'x' + FloatToStr(S.y);
end;

现在你可以做

procedure TForm1.Button1Click(Sender: TObject);
var
  S: TSizeString;
begin
  S := '20x30';             // works
  ShowMessage(S);
  S := 'Hello World!';      // exception raised
  ShowMessage(S);
end;

在旧版本的 Delphi 中,您只需编写一个类,或创建一个基本记录来保存您的大小(然后,当然,您可以创建在此类记录和格式化字符串之间转换的函数)。

【讨论】:

  • 不错的演示,但 OP 没有解决方案,因为它不适用于 Delphi 7。
【解决方案2】:

像 TFileName 和 TCaption 这样的特殊类型并没有什么特别的,就像 Andreas 提到的那样,但它们可用于在 IDE 中注册特定的属性编辑器。这将有助于通过对象检查器输入这些值。

要真正强制执行这样的值,如果您的字符串是对象的属性,您可以为它编写一个 setter。

否则,我应该创建一个 TSize 类,该类具有两个整数的属性,以及一个将其属性组合为字符串的 AsString 属性。

type
  TSize = class
  private
    FLeftInt, FRightInt: Integer;
    function GetString: string;
    procedure SetString(Value: string);
  public
    property LeftInt: Integer read FLeftInt write FLeftInt;
    property RightInt: Integer read FRightInt write FRightInt;
    property AsString: string read GetString write SetString;
  end;

function TSize.GetString: string;
begin
  Result := Format('%dx%d', [FLeftInt, FRightInt]);
end;

function TSize.SetString(Value: string);
begin
  // Validate and parse Value. Set LeftInt and RightInt.
end;

【讨论】:

  • 这几乎和我已经拥有的一样,TDimensions,但我想知道是否有更轻的版本,因为我一次可能要处理数千个。
  • 其实只是一个想法,我宁愿存储字符串而不是2个整数,并根据需要将其解析出来以供阅读。这将允许用户输入和维护不同的格式,只要他们遵循一些基本规则。同时,我可能会将 AsString 属性发布为类的默认值……对吗?
  • 嗯,我的意思是更轻的重量,因为使用记录而不是类,不必创建/销毁这个类会很棒,但不会发生:D
  • 好吧,你可以使用object,因为你被困在 D7 上。在现代 Delphi 中使用 op 会很流畅。过载和记录。你在使用 FastMM 吗?你分析过代码了吗?
  • 不,只是指出信息。我在D6上呆了很长时间,18个月前才升级。但是您应该使用 FastMM 进行堆分配,并且对象可以在 D7 中为您提供堆栈分配的 OOP。
【解决方案3】:

最简单的方法就是使用一个函数,并且在定义字符串时始终使用它...

function MyString(numA, numB: single) : string;
begin
    Result := FloatToStr(numA) + 'x' + FloatToStr(numB)
end;

如果你想变得更高级,你可以将它作为一个类来实现,它允许将字符串直接赋值为属性,但它会解析字符串以符合要求。

【讨论】:

  • 谢谢,但在这种情况下,我想明确定义某种类型,而不仅仅是调整属性的工作方式。
猜你喜欢
  • 2021-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多