Articles   Members Online: 3
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
How to convert a decimal number string to a Base36 number string Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
16-Mar-03
Category
Object Pascal-Strings
Language
Delphi 2.x
Views
103
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Jonas Bilinkevicius

I have a 20 digit string, all numbers, and I would like to convert this to a Base36 
to take up less space. I have tried the Borland Radix() routine but this would not 
work on such a large number. Does anyone have an idea on how to convert the decimal 
number string to aBase36 number string?

Answer:

Solve 1:

Does the encoding have to result in a string having only "printable" characters 
(#32..#126) or is any byte value allowed? If so an easy packing method not 
requiring any complex calculation would be BCD: pack two digits into a byte, giving 
a 50% size reduction:

1   function NumStringToBCD(const inStr: string): string;
2   
3     function Pack(ch1, ch2: Char): Char;
4     begin
5       Assert((ch1 >= '0') and (ch1 <= '9'));
6       Assert((ch2 >= '0') and (ch2 <= '9'));
7       {Ord('0') is $30, so we can just use the low nybble of the character as value.}
8       Result := Chr((Ord(ch1) and $F) or ((Ord(ch2) and $F) shl 4))
9     end;
10  
11  var
12    i: Integer;
13  begin
14    if Odd(Length(inStr)) then
15      Result := NumStringToBCD('0' + inStr)
16    else
17    begin
18      SetLength(Result, Length(inStr) div 2);
19      for i := 1 to Length(Result) do
20        Result[i] := Pack(inStr[2 * i - 1], inStr[2 * i]);
21    end;
22  end;
23  
24  function BCDToNumString(const inStr: string): string;
25  
26    procedure UnPack(ch: Char; var ch1, ch2: Char);
27    begin
28      ch1 := Chr((Ord(ch) and $F) + $30);
29      ch2 := Chr(((Ord(ch) shr 4) and $F) + $30);
30      Assert((ch1 >= '0') and (ch1 <= '9'));
31      Assert((ch2 >= '0') and (ch2 <= '9'));
32    end;
33  
34  var
35    i: Integer;
36  begin
37    SetLength(Result, Length(inStr) * 2);
38    for i := 1 to Length(inStr) do
39      UnPack(inStr[i], Result[2 * i - 1], Result[2 * i]);
40  end;
41  
42  procedure TForm1.Button1Click(Sender: TObject);
43  var
44    S1, S2: string;
45  begin
46    S1 := '15151515151515151515';
47    S2 := NumStringToBCD(S1);
48    memo1.lines.add('S1: ' + S1);
49    memo1.lines.add('Length(S2): ' + IntToStr(Length(S2)));
50    memo1.lines.add('S2 unpacked again: ' + BCDToNumString(S2));
51  end;



Solve 2:

This DecimalStrToBase36Str seems to work on smaller inputs, but I suggest that you 
check output on the larger inputs.

52  { ... }
53  const
54    Base36Digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
55  
56  type
57    tArrayElement = Byte;
58    tDoubleElement = Word;
59    {tArrayElement  = Word;}
60    {tDoubleElement = LongWord;}
61  
62  const
63    SizeOfAryElem = SizeOf(tArrayElement);
64    BitsInBufElem = SizeOfAryElem * 8;
65  
66  function DecimalStrToBase36Str(const Value: string): string;
67  var
68    Man: array[0..19] of tArrayElement;
69    NbrManElem, Cry, i, j, n, Tmp: integer;
70    Tmp1, Tmp2: packed record
71      case byte of
72        0: (Wd: tDoubleElement);
73        1: (Lo, Hi: tArrayElement);
74    end;
75  begin
76    n := length(Value);
77    if n <> 20 then
78      raise Exception.CreateFmt('Input string must be 20 decimal digits, not %d 
79  digits'
80        [n]);
81    NbrManElem := 0;
82    for i := 1 to n do
83    begin
84      Cry := ord(Value[i]) - ord('0');
85      if (Cry < 0) or (Cry > 9) then
86        raise Exception.CreateFmt('Input string contains non-decimal digit (%s)',
87          [Value[i]]);
88      {Multiply accumulation by 10 and add k:}
89      for j := 0 to NbrManElem - 1 do
90      begin
91        Tmp := Man[j] * 10 + Cry;
92        Man[j] := Tmp and $FF;
93        Cry := Tmp shr 8;
94      end;
95      if Cry <> 0 then
96      begin
97        Inc(NbrManElem);
98        Man[NbrManElem - 1] := Cry;
99      end;
100   end;
101   SetLength(Result, 14);
102   for i := 14 downto 1 do
103   begin
104     {Divide by 36 and save the remainder:}
105     Tmp1.Hi := 0;
106     for j := NbrManElem - 1 downto 0 do
107     begin
108       Tmp1.Lo := Man[j];
109       Tmp2.Wd := Tmp1.Wd div 36;
110       Assert(Tmp2.Hi = 0);
111       Man[j] := Tmp2.Lo;
112       Tmp1.Hi := Tmp1.Wd mod 36;
113     end;
114     Result[i] := Base36Digits[Tmp1.Hi + 1];
115     if (NbrManElem > 0) and (Man[NbrManElem - 1] = 0) then
116     begin
117       dec(NbrManElem);
118     end;
119   end;
120 end;


			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC