是否可以声明具有不受0/1开始的受限长度的字符串类型?

Mar*_*ato 3 delphi delphi-xe2

在Delphi中,可以声明整数值的子范围.例如:

type
  myInt = 2..150
Run Code Online (Sandbox Code Playgroud)

这将myInt类型的值限制为2到150之间的值.但是,如果我想限制字符串的长度怎么办?

如果我写:

type 
  myString = string [150]
Run Code Online (Sandbox Code Playgroud)

我将mystring声明为150字节长,并将长度限制为从0,1,2等到150.但是,如何将长度限制在2到150之间,例如?当然,我可以检查字符串的长度并引发异常,但Delphi是否包含一些特定于这种情况的语法,类似于子范围的样式?

这显然不起作用,但我想要像:

type
  myString = string[2..150] 
Run Code Online (Sandbox Code Playgroud)

如果不可能,那么我可以检查长度,提出异常等.


试试这段代码:

var
 str1, str2, str3: TRestrictedString;
begin
  str1.Create(2, 5, 'pp');
  str2.Create(2, 5, 'aaaa');
  str3.Create(2, 10, str1 + str2);
  writeln (str3.getstring)
end
Run Code Online (Sandbox Code Playgroud)

要么:

var
 str1, str2, str3: TRestrictedString;
begin
  str1.Create(2, 5, 'pp');
  str2.Create(2, 5, 'aaaa');
  str3.Create(2, 10);
  str3.SetString(str1 + str2);
  writeln (str3.getstring)
end
Run Code Online (Sandbox Code Playgroud)

要么:

var
 str1, str2, str3: TRestrictedString;
begin
  str1.Create(2, 5, 'pp');
  str2.Create(2, 5, 'aaaa');
  str3.Create(2, 10);
  str3 := str1 + str2;
  writeln(str3.GetString);
end
Run Code Online (Sandbox Code Playgroud)

所有这些都引发了例外.有可能解决这个问题吗?对于字符串的多个操作是否有必要将函数拆分为更多部分?在构造函数中,添加一个检查更好minlength < maxlength吗?如果我设置minlength > maxlength它会引发异常.

And*_*and 14

我会做

type
  TRestrictedString = record
  strict private type
    TBounds = record
      MinLength,
      MaxLength: integer;
    end;
  strict private
    FStr: string;
  public
    Bounds: TBounds;
    procedure SetString(const AString: string);
    function GetString: string;
    constructor Create(AMinLength, AMaxLength: integer); overload;
    constructor Create(AMinLength, AMaxLength: integer; const AString: string); overload;
    constructor Create(const AString: string); overload;
    class operator Implicit(S: string): TRestrictedString;
    class operator Implicit(S: TRestrictedString): string;
    class operator Equal(const A, B: TRestrictedString): boolean;
    class operator NotEqual(const A, B: TRestrictedString): boolean;
    class operator Add(const A, B: TRestrictedString): TRestrictedString;
  end;

{ TRestrictedString }


constructor TRestrictedString.Create(AMinLength, AMaxLength: integer);
begin
  Bounds.MinLength := AMinLength;
  Bounds.MaxLength := AMaxLength;
  FStr := '';
end;

constructor TRestrictedString.Create(AMinLength, AMaxLength: integer;
  const AString: string);
begin
  Bounds.MinLength := AMinLength;
  Bounds.MaxLength := AMaxLength;
  SetString(AString);
end;

class operator TRestrictedString.Add(const A,
  B: TRestrictedString): TRestrictedString;
begin
  result.Bounds := A.Bounds;
  result.SetString(A.GetString + B.GetString);
end;

constructor TRestrictedString.Create(const AString: string);
begin
  Bounds.MinLength := 0;
  Bounds.MaxLength := MaxInt;
  FStr := AString;
end;

class operator TRestrictedString.Equal(const A, B: TRestrictedString): boolean;
begin
  result := A.GetString = B.GetString;
end;

function TRestrictedString.GetString: string;
begin
  result := FStr;
end;

class operator TRestrictedString.Implicit(S: TRestrictedString): string;
begin
  result := S.GetString;
end;

class operator TRestrictedString.NotEqual(const A,
  B: TRestrictedString): boolean;
begin
  result := A.GetString <> B.GetString;
end;

class operator TRestrictedString.Implicit(S: string): TRestrictedString;
begin
  result.Create(S);
end;

procedure TRestrictedString.SetString(const AString: string);
begin
  with Bounds do
    if (length(AString) < MinLength) or (length(AString) > MaxLength) then
      raise Exception.Create('Invalid length of string.');
  FStr := AString;
end;
Run Code Online (Sandbox Code Playgroud)

现在你可以做很自然的事情,比如

procedure TForm1.Button1Click(Sender: TObject);
var
  str: TRestrictedString;
begin
  str.Create(5, 10);         // Create a string w/ length 5 to 10 chrs
  str.SetString('Testing!'); // Assign a compatible string
  ShowMessage(str);          // Display the string
end;
Run Code Online (Sandbox Code Playgroud)

你也可以做

str.Create(5, 10, 'Testing!');
ShowMessage(str);
Run Code Online (Sandbox Code Playgroud)

您可以通常的方式添加字符串:

var
  s1, s2, s3: TRestrictedString;
begin
  s1.Create(2, 10, 'Hi ');
  s2.Create(2, 10, 'there!');
  s3 := s1 + s2;
  ShowMessage(s3);
end;
Run Code Online (Sandbox Code Playgroud)

甚至

var
  s1, s3: TRestrictedString;
begin
  s1.Create(2, 10, 'Hi ');
  s3 := s1 + 'there!';
  ShowMessage(s3);
Run Code Online (Sandbox Code Playgroud)

当您添加两个TRestrictedStrings或1 TRestrictedString和a时string,结果将具有与第一个操作数相同的限制.你可以试试

var
  str: TRestrictedString;
begin
  str.Create(5, 10);
  str.SetString('Testing!');
  str := str + '!!';
  ShowMessage(str);
Run Code Online (Sandbox Code Playgroud)

哪个会起作用,但不起作用

var
  str: TRestrictedString;
begin
  str.Create(5, 10);
  str.SetString('Testing!');
  str := str + '!!!';
  ShowMessage(str);
Run Code Online (Sandbox Code Playgroud)

请注意,为a 分配 a 也会分配字符串的'bounds',也就是说,will将绑定设置为和.因此,无论如何限制,任务都将始终有效.stringTRestrictedStringTRestrictedString0MaxInts: TRestrictedStrings := 'some string'

更新:Chris Rolliston使用这个答案作为一篇非常有趣的文章的灵感来源.

  • 努力+1.但我认为这实际上证明了实际的答案是"是的,但这不值得麻烦." (4认同)
  • +1这个Delphi记录和重载功能的优秀例子,可以创建非常灵活的值类型. (2认同)