Is possible to declare string type with restricted length that doesn't start from 0/1?
In Delphi it is possible to declare subranges for integer values. For example:
type
myInt = 2..150
Which restricts values of myInt type to values from 2 to 150. But what if I want to restrict the length of a string?
If I write:
type
myString = string [150]
I declare mystring to be 150 bytes long and restrict the length to be from 0, 1, 2, etc. up to 150. But how do I restrict the length to between 2 and 150, for example? Of course, I can check the length of a string and raise an exception, but does Delphi include some syntax specific to this situation, similar in style to subranges?
This obviously does not work, but I would like something like:
type
myString = string[2..150]
If it is not possible, then I can just check length, raise exception, etc.
trying this code:
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
or:
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
or:
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
All of these raise an exception. Is possible to solve this? For multiple operations on a strin开发者_StackOverflow社区g is it necessary to split the function into more parts?
In the constructor, is it better to add a check that minlength < maxlength
? If I set minlength > maxlength
it raises an exception.
I would do
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;
Now you can do very natural things, like
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;
You can also do just
str.Create(5, 10, 'Testing!');
ShowMessage(str);
You can add string the usual way:
var
s1, s2, s3: TRestrictedString;
begin
s1.Create(2, 10, 'Hi ');
s2.Create(2, 10, 'there!');
s3 := s1 + s2;
ShowMessage(s3);
end;
or even
var
s1, s3: TRestrictedString;
begin
s1.Create(2, 10, 'Hi ');
s3 := s1 + 'there!';
ShowMessage(s3);
When you add two TRestrictedString
s, or one TRestrictedString
and a string
, the result will have the same restriction as the first operand. You can try
var
str: TRestrictedString;
begin
str.Create(5, 10);
str.SetString('Testing!');
str := str + '!!';
ShowMessage(str);
which will work, but not
var
str: TRestrictedString;
begin
str.Create(5, 10);
str.SetString('Testing!');
str := str + '!!!';
ShowMessage(str);
Just beware that assigning a string
to a TRestrictedString
will also assign the 'bounds' of the string, that is, the TRestrictedString
will have bounds set to 0
and MaxInt
. Thus, no matter how a s: TRestrictedString
is restricted, an assignment s := 'some string'
will always work.
Update: Chris Rolliston used this answer as inspiration for a very interesting article.
精彩评论