Recent

Author Topic: [Solved] S10 Tracking numbers  (Read 1144 times)

Zvoni

  • Hero Member
  • *****
  • Posts: 3138
Re: [Solved] S10 Tracking numbers
« Reply #15 on: October 15, 2025, 08:23:50 am »
Changed my approach a bit.
The String-Handling was bugging me.

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$mode objfpc}{$H+}
  3. Uses Classes, Sysutils, regexpr;
  4.  
  5. Const
  6.   S10:String='RC473124829DE';
  7.   Pattern:String='(\w{2})(\d{9})(\w{2})';
  8.   Weights:array[0..7] of Integer=(8,6,4,2,3,5,9,7);
  9.   CheckDigits:Array[0..11] Of Integer=(0,1,2,3,4,5,6,7,8,9,0,5);
  10.  
  11. Var
  12.   SV,SN,CO:String;
  13.   CD:Integer;
  14.   IsValid:Boolean;
  15.  
  16. Function CheckS10(Const AS10:String;var AService:String;var ASerialNo:String;Var ACheckDigit:Integer;var ACountry:String):Boolean;
  17. Var
  18.   regex:TRegExpr;
  19.   b:Boolean;
  20.   i:Integer;
  21.   s:Integer;
  22.   sn:Integer;
  23.   cd:Integer;
  24. Begin
  25.   Result:=False;
  26.   s:=0;
  27.   If Length(AS10)<>13 Then Exit;
  28.   regex:=TRegexpr.Create;
  29.   regex.ModifierI:=True;
  30.   regex.ModifierG:=True;
  31.   regex.Expression:=Pattern;
  32.   regex.InputString:=AS10;
  33.   b:=regex.Exec;
  34.   If Not b Then Exit;                            //Regex failed
  35.   If regex.SubExprMatchCount<>3 Then Exit;       //Must be 3 SubMatches, else not valid S10-Format
  36.   AService:=Regex.Match[1];                      //Service
  37.   ASerialNo:=LeftStr(regex.Match[2],8);          //Left 8 characters are the SerialNumber
  38.   sn:=ASerialNo.ToInteger;                       //SerialNumber as Integer
  39.   ACheckDigit:=regex.Match[2].ToInteger Mod 10;  //CheckDigit As Integer
  40.   ACountry:=regex.Match[3];                      //Country Of Origin
  41.   For i:=7 DownTo 0 Do                           //Iterating backwards, since parsing the Serialnumber from right to left
  42.     Begin
  43.       cd:=sn mod 10;                             //Get the right most Digit
  44.       s:=s+cd*Weights[i];                        //Build Sum
  45.       sn:=sn Div 10;                             //Cut off right most Digit
  46.     end;
  47.   cd:=CheckDigits[11-(s mod 11)];                //Get the CheckDigit from Lookup-Array
  48.   Result:=(ACheckDigit=cd);
  49.   regex.Free;
  50. End;
  51.  
  52. begin
  53.   IsValid:=CheckS10(S10,SV,SN,CD,CO);
  54.   Writeln(S10);
  55.   Writeln(SV);
  56.   Writeln(SN);
  57.   Writeln(CD);
  58.   Writeln(CO);
  59.   Writeln(IsValid);
  60.   Readln;
  61. end.
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

creaothceann

  • Full Member
  • ***
  • Posts: 203
Re: [Solved] S10 Tracking numbers
« Reply #16 on: October 15, 2025, 09:56:40 am »
Objects should always be freed...

Code: Pascal  [Select][+][-]
  1. program Project1;  {$mode ObjFPC}  {$H+}
  2. uses
  3.         Classes,
  4.         RegExpr,
  5.         Sysutils;
  6.  
  7.  
  8. function Check_S10(
  9.         const S10        : string;
  10.         out   Service    : string;
  11.         out   Serial     : string;
  12.         out   CheckDigit : integer;
  13.         out   Country    : string) : boolean;
  14. const
  15.         CheckDigits : array[0..11] of integer = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 5);
  16.         Weights     : array[0.. 7] of integer = (8, 6, 4, 2, 3, 5, 9, 7);
  17. var
  18.         i, sum : integer;
  19.         RegEx  : TRegExpr;
  20. begin
  21.         if (Length(S10) <> 13) then exit(false);
  22.         RegEx := TRegExpr.Create;
  23.         try
  24.                 RegEx.ModifierI   := True;
  25.                 RegEx.ModifierG   := True;
  26.                 RegEx.Expression  := '(\w{2})(\d{9})(\w{2})';  // pattern
  27.                 RegEx.InputString := S10;
  28.                 if (not RegEx.Exec              ) then exit(False);
  29.                 if (RegEx.SubExprMatchCount <> 3) then exit(False);
  30.                 Service    := RegEx.Match[1];
  31.                 Serial     := LeftStr(RegEx.Match[2], 8);
  32.                 CheckDigit := RegEx.Match[2].ToInteger mod 10;
  33.                 Country    := RegEx.Match[3];
  34.                 sum        := 0;    for i := 0 to 7 do  Inc(sum, StrToInt(Serial[i]) * Weights[i]);  // get sum of serial chars
  35.                 Result     := (CheckDigit = CheckDigits[11 - (sum mod 11)]);                         // check with LUT
  36.         finally
  37.                 RegEx.Free;
  38.         end;
  39. end;
  40.  
  41.  
  42. // main program
  43.  
  44. const
  45.         S10 : string = 'RC473124829DE';
  46.  
  47. var
  48.         CheckDigit               : integer;
  49.         Service, Serial, Country : string;
  50.         valid                    : boolean;
  51.  
  52.  
  53. begin
  54.         valid := Check_S10(S10, Service, Serial, CheckDigit, Country);
  55.         WriteLn(S10       );
  56.         WriteLn(Service   );
  57.         WriteLn(Serial    );
  58.         WriteLn(CheckDigit);
  59.         WriteLn(Country   );
  60.         WriteLn(valid     );
  61.         ReadLn;
  62. end.
Quote from: Thaddy
And don't start an argument, I am right.
Quote from: Thaddy
You have a thorough misunderstanding of what I wrote. Can you provide an example this time? I doubt it. (because you never do out of incompentence)

Zvoni

  • Hero Member
  • *****
  • Posts: 3138
Re: [Solved] S10 Tracking numbers
« Reply #17 on: October 15, 2025, 10:03:56 am »
Objects should always be freed...

Looking at my Line 49..... *confused*

and i don't understand the Try/Finally...
There is nothing that can blow up.
And in your code there is the String-Handling again....
Unneccessary overhead...
« Last Edit: October 15, 2025, 10:10:21 am by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

creaothceann

  • Full Member
  • ***
  • Posts: 203
Re: [Solved] S10 Tracking numbers
« Reply #18 on: October 15, 2025, 10:48:15 am »
Objects should always be freed...

Looking at my Line 49..... *confused*

What happens when the function exits in line 34 or 35?


And in your code there is the String-Handling again.... Unneccessary overhead...

ToInteger is also string handling. If you want the fastest code you should use the
Code: Pascal  [Select][+][-]
  1. (byte(SerialNumber[i]) - ord('0'))
version by BrunoK.

Compiling the regular expression solver at runtime is also possibly the slowest part of the program, only amortized if the RegEx is created once at program start and then cached for subsequent S10 checks.

Dividing by 10 / getting modulo 10 is not the fastest way either.
« Last Edit: October 15, 2025, 10:53:24 am by creaothceann »
Quote from: Thaddy
And don't start an argument, I am right.
Quote from: Thaddy
You have a thorough misunderstanding of what I wrote. Can you provide an example this time? I doubt it. (because you never do out of incompentence)

Zvoni

  • Hero Member
  • *****
  • Posts: 3138
Re: [Solved] S10 Tracking numbers
« Reply #19 on: October 15, 2025, 11:10:43 am »
Objects should always be freed...

Looking at my Line 49..... *confused*

What happens when the function exits in line 34 or 35?
ARGGHH..... You're right. Missed that one.
Yep, Memory-Leak if premature Function-Exit.

Everything else: I'll take your word for it.
Am not really knowledgable in that
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

BrunoK

  • Hero Member
  • *****
  • Posts: 721
  • Retired programmer
Re: [Solved] S10 Tracking numbers
« Reply #20 on: October 15, 2025, 04:59:34 pm »
Correction for my code re checksum for 10 and 11 using  Zvoni array.
Code: Pascal  [Select][+][-]
  1.   function ParseAndValidateAS10(aTracking: string; out aoInfo: TS10Info): boolean;
  2.   const
  3.     Weights: array[0..7] of byte = (8, 6, 4, 2, 3, 5, 9, 7);
  4.     CheckDigits : array[0..11] of integer = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 5);
  5.   var
  6.     i, RunSum: integer;
  7.   begin
  8.     Result := False;
  9.     aoInfo := Default(TS10Info);
  10.     // quick exit length has to be 13
  11.     if Length(ATracking) <> 13 then
  12.       Exit;
  13.     system.move(aTracking[1], aoInfo, 13);
  14.     with aoInfo do begin
  15.       RunSum := 0;
  16.       for i := 0 to Length(SerialNumber) - 1 do begin
  17.         // check letter pattern
  18.         if not (SerialNumber[i] in ['0'..'9']) then
  19.           exit;
  20.         Inc(RunSum, Weights[i] * (byte(SerialNumber[i]) - Ord('0')));
  21.       end;
  22.       RunSum := 11 - (RunSum mod 11);                          // Edit 25.10.15
  23.       if CheckDigits[RunSum]<>Byte(CheckDigit)-ord('0') then   //      25.10.15
  24.         exit;
  25.       Result := True;
  26.       IsValid := Result;
  27.     end;
  28.   end;
  29.  

 

TinyPortal © 2005-2018