2

I need to use different procedure depending on the Edittext.text

i need to call ProcessA(value: string); with Parameters of last 4 Char of string if Edittext.text's first 4 char are string and next 4 are number.

and Call ProcessB(value:integer) with last four numbers as parameter if all 8 char are numbers ?

For Example: If EditText.Text is ASDF1234 then i'll call ProcessA and if EdiText.Text is 12345678 then i need to call ProcessB.

Show Error if string is like ASD12345 or ASDFG123 or 1234567A or if Numbers are in decimal.

How can i verify this ?

Rohn
  • 33
  • 5

1 Answers1

4
var
  Text: string;

  function CharInRange(C, FirstC, LastC: char): boolean; inline;
  begin
    Result := (C >= FirstC) and (C <= LastC);
  end;

  function IsDigitsOnly(const S: string;
    FirstIdx, LastIdx: integer): boolean;
  var
    I: integer;
  begin
    for I := FirstIdx to LastIdx do
    begin
      if not CharInRange(S[I], '0', '9') then
      begin
        Result := False;
        Exit;
      end;
    end;
    Result := True;
  end;

  function IsUpcaseLettersOnly(const S: string;
    FirstIdx, LastIdx: integer): boolean;
  var
    I: integer;
    C: char;
  begin
    for I := FirstIdx to LastIdx do
    begin
      C := S[I];
      if not CharInRange(C, 'A', 'Z') then
      begin
        Result := False;
        Exit;
      end;
    end;
    Result := True;
  end;

  procedure BadInput;
  begin
    raise Exception.Create('Bad Input');
  end;

begin
  Text := EditText.Text;
  if Length(Text) <> 8 then
  begin
    BadInput;
  end
  else if IsUpcaseLettersOnly(Text, 1, 4)
          and IsDigitsOnly(Text, 5, 8) then
  begin
    ProcessA(Copy(Text, 5, 4));
  end
  else if IsDigitsOnly(Text, 1, 8) then
  begin
    ProcessB(StrToInt(Copy(Text, 5, 4)));
  end
  else
  begin
    BadInput;
  end;
end;

Alternatively

uses
  ..., System.RegularExpressions;

var
  Text: string;
begin
  Text := EditText.Text;
  // I know this can be done better using a
  // single regex expression with capture groups, 
  // but I don't know the correct code to do that...
  if TRegEx.IsMatch(Text, '^[A-Z]{4}[0-9]{4}$') then
  begin
    ProcessA(Copy(Text, 5, 4));
  end
  else if TRegEx.IsMatch(Text, '^[0-9]{8}$') then
  begin
    ProcessB(StrToInt(Copy(Text, 5, 4)));
  end
  else
  begin
    raise Exception.Create('Bad Input');
  end;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    Instead of declaring 2 local functions, would it be better to use TCharHelper.IsLetter and TCharHelper.IsDigit out of the Systems.Character unit? – Ancaron May 17 '19 at 09:12
  • @Ancaron can't resolve `System.Character.TCharHelper` in delphi rio. – Rohn May 17 '19 at 09:19
  • 1
    @Rohn you don't use `TCharHelper` directly, you call its methods on a `Char` variable, eg : `uses System.Character; ... if S[i].IsLetter then ...` – Remy Lebeau May 17 '19 at 09:34
  • @Remy just above to mention it. Thank You so much For alternative one too. – Rohn May 17 '19 at 09:34
  • @Ancaron `IsLetter` and `IsDigit` allow letter/digit characters that are outside of the ASCII range – Remy Lebeau May 17 '19 at 09:35
  • @RemyLebeau `^[A-Z]{4}[0-9]{4}$` in `Regext.IsMatch` what difference they makes comparing `[A-Z]{4}[0-9]{4}` – Rohn May 20 '19 at 09:54