base_convert 3.1.191231 → 4.0.200111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +169 -127
- data/lib/base_convert.rb +4 -1
- data/lib/base_convert/base.rb +24 -0
- data/lib/base_convert/base_convert.rb +8 -2
- data/lib/base_convert/chars.rb +59 -0
- data/lib/base_convert/configuration.rb +86 -59
- data/lib/base_convert/digits.rb +96 -0
- data/lib/base_convert/from_to.rb +15 -9
- data/lib/base_convert/number.rb +46 -45
- metadata +6 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8c43a6429ac3a041f6f01f535b4159087a89e1373c95069617bd134b4f0e5e03
|
|
4
|
+
data.tar.gz: 7cbd6306d8ece168d0b5548f1b1e208911be94040d405753c4fb83e1c08af83a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1b1ce6da4bdeb6d589b2b486519b91894eef24502968dc2fa1034e3007704d8791031f89af1e42d92116067c52f50d0b5c2a73ae21ff743975b1b6718d388042
|
|
7
|
+
data.tar.gz: 11cd53a28e2c169186f2c911345c751990ff48843133add22153bb35ff857208b09252f6c117df737601817b4b41d1870ab32eec6678f2e846ee41887cf30d3c
|
data/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# BaseConvert
|
|
2
2
|
|
|
3
|
+
* [VERSION 4.0.200111](https://github.com/carlosjhr64/base_convert/releases)
|
|
3
4
|
* [github](https://www.github.com/carlosjhr64/base_convert)
|
|
4
5
|
* [rubygems](https://rubygems.org/gems/base_convert)
|
|
5
6
|
|
|
@@ -9,7 +10,7 @@ BaseConvert - Number base conversion.
|
|
|
9
10
|
|
|
10
11
|
Converts positive integers to different bases:
|
|
11
12
|
Binary, octal, hexadecimal, decimal, or any arbitrary base.
|
|
12
|
-
"Out of the box" handling of up to base
|
|
13
|
+
"Out of the box" handling of up to base 95(:print: characters).
|
|
13
14
|
Allows for arbitrary choice of alphabet(digits).
|
|
14
15
|
|
|
15
16
|
See also rosettacode.org's [Non-decimal radices convert](http://rosettacode.org/wiki/Non-decimal_radices/Convert).
|
|
@@ -21,21 +22,24 @@ See also rosettacode.org's [Non-decimal radices convert](http://rosettacode.org/
|
|
|
21
22
|
#toi string, base, digits #=> integer
|
|
22
23
|
BaseConvert.toi 'FF', 16, '0123456789ABCDEF' #=> 255
|
|
23
24
|
|
|
24
|
-
#
|
|
25
|
-
BaseConvert.
|
|
25
|
+
#tos integer, base, digits #=> string
|
|
26
|
+
BaseConvert.tos 255, 16, '0123456789ABCDEF' #=> "FF"
|
|
26
27
|
|
|
27
28
|
# FromTo
|
|
28
29
|
c = BaseConvert::FromTo.new base: 16, digits: '0123456789ABCDEF', to_base: 7, to_digits: 'abcdefg'
|
|
29
30
|
c['FFF'] #=> "begea"
|
|
31
|
+
c.inspect #=> "16:P95,7:abfg"
|
|
30
32
|
|
|
31
33
|
# Number
|
|
32
34
|
n = BaseConvert::Number.new 'FF', base: 16, digits: '0123456789ABCDEF'
|
|
33
35
|
n.to_i #=> 255
|
|
34
36
|
n.to_s #=> "FF"
|
|
37
|
+
n.inspect #=> FF 16:P95
|
|
35
38
|
#
|
|
36
39
|
n = n.to_base 64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
37
40
|
n.to_s #=> "D/"
|
|
38
41
|
n.to_i #=> 255
|
|
42
|
+
n.inspect #=> D/ 64:B64
|
|
39
43
|
|
|
40
44
|
## INSTALL:
|
|
41
45
|
|
|
@@ -43,142 +47,180 @@ See also rosettacode.org's [Non-decimal radices convert](http://rosettacode.org/
|
|
|
43
47
|
|
|
44
48
|
## BUT WAIT, THERE'S MORE:
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
### module BaseConvert
|
|
51
|
+
|
|
52
|
+
* `#toi(string=to_s String, base=@base Integer, digits=@digits String) #=> Integer`
|
|
53
|
+
* `#tos(integer=to_i Integer, base=@base Integer, digits=@digits String) #=> String`
|
|
54
|
+
* `#ascii_ordered?(digits=@digits String) #=> TrueClass|FalseClass`
|
|
55
|
+
|
|
56
|
+
Exemplar:
|
|
57
|
+
|
|
58
|
+
class MyClass
|
|
59
|
+
include BaseConvert
|
|
60
|
+
attr_accessor :to_s, :to_i, :base, :digits
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
obj = MyClass.new
|
|
64
|
+
obj.digits = '!@#$%^&*()'
|
|
65
|
+
obj.base = 10
|
|
66
|
+
|
|
67
|
+
obj.to_s = '@'
|
|
68
|
+
obj.toi #=> 1
|
|
69
|
+
|
|
70
|
+
obj.to_i = 3
|
|
71
|
+
obj.tos #=> "$"
|
|
72
|
+
|
|
73
|
+
obj.ascii_ordered? #=> false
|
|
74
|
+
obj.digits = 'ABCDEFGHIJKLMNOP'
|
|
75
|
+
obj.ascii_ordered? #=> true
|
|
76
|
+
|
|
77
|
+
### Hash DIGITS
|
|
78
|
+
|
|
79
|
+
#### DIGITS methods
|
|
80
|
+
|
|
81
|
+
* `DIGITS.get(key Symbol) #=> String|Symbol|NilClass`
|
|
82
|
+
* `DIGITS.registry(digits=nil NilClass|String) #=> Array(Symbol)|Symbol`
|
|
83
|
+
* `DIGITS.label(digits String) #=> String`
|
|
84
|
+
* `DIGITS.memoize!(key=registry Symbol|Array(Symbol))`
|
|
85
|
+
* `DIGITS.forget!(key=registry Symbol|Array(Symbol))`
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
Exemplar:
|
|
89
|
+
|
|
90
|
+
include BaseConvert
|
|
91
|
+
DIGITS.get(:P95) #=> :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
|
|
92
|
+
DIGITS[:P95]
|
|
93
|
+
#=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%\"'`_ "
|
|
94
|
+
DIGITS.registry #=> [:P95, :B64, :U47, :G94, :Q91, :W63]
|
|
95
|
+
DIGITS.registry('347') #=> :U47
|
|
96
|
+
DIGITS.registry('0') #=> :P95
|
|
97
|
+
DIGITS.registry('AB') #=> :B64
|
|
98
|
+
DIGITS.registry('Cukoe') #=> nil
|
|
99
|
+
DIGITS.label('Cukoe') #=> :Cuoe
|
|
100
|
+
DIGITS.label('AaBbCcXxYyZz') #=> :AaZz
|
|
101
|
+
DIGITS[:N] #=> "0123456789"
|
|
102
|
+
DIGITS.get(:N) #=> nil
|
|
103
|
+
DIGITS.memoize!(:N)
|
|
104
|
+
DIGITS.get(:N) #=> "0123456789"
|
|
105
|
+
DIGITS.forget!(:N)
|
|
106
|
+
DIGITS.get(:N) #=> nil
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
#### DIGITS constructions
|
|
110
|
+
|
|
111
|
+
`BaseConvert::DIGITS` will take a `Symbol` representation of `Regexp` patterns.
|
|
112
|
+
See [Ruby-Doc's Regexp](https://ruby-doc.org/core-2.7.0/Regexp.html) documentation
|
|
113
|
+
for a full list of keys. The following provides an exemplar survey:
|
|
114
|
+
|
|
115
|
+
# Character Classes
|
|
116
|
+
# Selected from ASCII 32..126
|
|
117
|
+
DIGITS[:w] #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
|
|
118
|
+
DIGITS[:d] #=> "0123456789"
|
|
119
|
+
# Note: :h was overridden, see :xdigit.
|
|
120
|
+
DIGITS[:h] #=> "0123456789ABCDEF"
|
|
121
|
+
DIGITS[:alpha] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
122
|
+
DIGITS[:graph]
|
|
123
|
+
#=> "!\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
124
|
+
DIGITS[:lower] #=> "abcdefghijklmnopqrstuvwxyz"
|
|
125
|
+
DIGITS[:punct] #=> "!\"\#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
|
126
|
+
DIGITS[:upper] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
127
|
+
DIGITS[:xdigit] #=> "0123456789ABCDEFabcdef"
|
|
128
|
+
|
|
129
|
+
# Character Properties
|
|
130
|
+
# Selected from ASCII 32..126
|
|
131
|
+
DIGITS[:Alnum] #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
132
|
+
DIGITS[:Any]
|
|
133
|
+
#=> " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
134
|
+
|
|
135
|
+
# General Category
|
|
136
|
+
# Selected from ASCII 32..126
|
|
137
|
+
DIGITS[:Ps] #=> "([{"
|
|
138
|
+
DIGITS[:Pe] #=> ")]}"
|
|
139
|
+
DIGITS[:S] #=> "$+<=>^`|~"
|
|
140
|
+
|
|
141
|
+
# Ranged Selections
|
|
142
|
+
# v<hex>w<hex>_<filter>
|
|
143
|
+
DIGITS[:v1d7d8w1d7e1_Any] #=> "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡"
|
|
144
|
+
# i<dec>j<dec>_<filter>
|
|
145
|
+
DIGITS[:i120488j120513_Any] #=> "𝚨𝚩𝚪𝚫𝚬𝚭𝚮𝚯𝚰𝚱𝚲𝚳𝚴𝚵𝚶𝚷𝚸𝚹𝚺𝚻𝚼𝚽𝚾𝚿𝛀𝛁"
|
|
146
|
+
|
|
147
|
+
# Specified Characters
|
|
148
|
+
# u<hex>
|
|
149
|
+
DIGITS[:u61u62] #=> "ab"
|
|
150
|
+
# k<dec>
|
|
151
|
+
DIGITS[:k97k98] #=> "ab"
|
|
152
|
+
|
|
153
|
+
# BaseConvert's Custom Sets
|
|
154
|
+
DIGITS[:bangs] #=> "!?"
|
|
155
|
+
DIGITS[:typers] #=> "$&@"
|
|
156
|
+
DIGITS[:operators] #=> "*+-/<=>^~"
|
|
157
|
+
DIGITS[:separators] #=> ",.:;|"
|
|
158
|
+
DIGITS[:scapes] #=> "#\\"
|
|
159
|
+
DIGITS[:groupers] #=> "()[]{}"
|
|
160
|
+
DIGITS[:quotes] #=> "\"'`"
|
|
161
|
+
DIGITS[:quoters] #=> "%\"'`"
|
|
162
|
+
DIGITS[:spacers] #=> "_ "
|
|
163
|
+
DIGITS[:ambiguous] #=> "012568BDGIOQSZl"
|
|
164
|
+
|
|
165
|
+
# Composition, add merge:
|
|
166
|
+
DIGITS[:d_ambiguous] #=> "0123456789BDGIOQSZl"
|
|
167
|
+
# Composition, add top:
|
|
168
|
+
DIGITS[:'d+ambiguous'] #=> "3479012568BDGIOQSZl"
|
|
169
|
+
# Composition, subtract:
|
|
170
|
+
DIGITS[:'d-ambiguous'] #=> "3479"
|
|
171
|
+
|
|
172
|
+
# Compositions used in BaseConvert
|
|
173
|
+
# :P95 is:
|
|
174
|
+
DIGITS[:alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers]
|
|
175
|
+
#=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%\"'`_ "
|
|
176
|
+
# :B64 is:
|
|
177
|
+
DIGITS[:LN_k43k47] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
178
|
+
# :U47 is:
|
|
179
|
+
DIGITS[:'alnum-ambiguous'] #=> "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"
|
|
180
|
+
|
|
181
|
+
### class FromTo
|
|
182
|
+
|
|
183
|
+
* `new(base: 10 Integer|Symbol|String, to_base: base, digits: :P95 String|Symbol|Integer, to_digits: digits) #=> FromTo`
|
|
184
|
+
* `#inspect #=> String`
|
|
185
|
+
* `#convert(counter String|Integer) #=> String`
|
|
48
186
|
|
|
49
|
-
|
|
50
|
-
Welcome to IRB...
|
|
51
|
-
>> require 'base_convert' #=> true
|
|
52
|
-
>> include BaseConvert #=> Object
|
|
53
|
-
|
|
54
|
-
`base_convert` provides three ways to convert a string representation of a number.
|
|
55
|
-
The first is functional. One can extend(import) the functions that do the conversions.
|
|
56
|
-
The conversion functions are `toi` and `tob`.
|
|
57
|
-
For example, the octal number "7777":
|
|
58
|
-
|
|
59
|
-
extend BaseConvert #=> main
|
|
60
|
-
digits = '01234567'
|
|
61
|
-
base = digits.length #=> 8
|
|
62
|
-
toi('7777', base, digits) #=> 4095
|
|
63
|
-
tob(4095, base, digits) #=> "7777"
|
|
64
|
-
|
|
65
|
-
You can work with arbitrary digits:
|
|
66
|
-
|
|
67
|
-
digits = ')!@#$%^&'
|
|
68
|
-
base = digits.length #=> 8
|
|
69
|
-
toi('&&&&', base, digits) #=> 4095
|
|
70
|
-
tob(4095, base, digits) #=> "&&&&"
|
|
71
|
-
|
|
72
|
-
Note that one can always explicitly specify the ordered digits to be used.
|
|
73
|
-
But for convenience, `base_convert` provides some predefined sets of digits:
|
|
74
|
-
|
|
75
|
-
* `GRAPH :graph :g`, the ASCII graph characters:
|
|
76
|
-
|
|
77
|
-
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
|
78
|
-
|
|
79
|
-
* `QGRAPH :qgraph :q`, the ASCII graph characters except `QUOTES`:
|
|
80
|
-
|
|
81
|
-
!#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~
|
|
82
|
-
|
|
83
|
-
* `BASE64 :base64 :b64`, the standard base 64 digits from people with no sense of order:
|
|
84
|
-
|
|
85
|
-
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
|
|
86
|
-
|
|
87
|
-
* `WORD_ :word_ :w_`, the ASCII word characters including `UNDERSCORE`:
|
|
88
|
-
|
|
89
|
-
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz
|
|
90
|
-
|
|
91
|
-
* `WORD :word :w`, the ASCII word characters except `UNDERSCORE`:
|
|
92
|
-
|
|
93
|
-
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
|
94
|
-
|
|
95
|
-
* `UNAMBIGUOUS :unambigous :u`, the characters in `WORD` without the `AMBIGUOUS` characters(B8G6I1l0OQDS5Z2):
|
|
96
|
-
|
|
97
|
-
3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz
|
|
98
|
-
|
|
99
|
-
* `G94 :g94` is the library's default defined as `WORD+QGRAPH.delete(WORD_)+QUOTES+UNDERSCORE`
|
|
100
|
-
|
|
101
|
-
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+,-./:;<=>?@[\]^{|}~"'`_
|
|
102
|
-
|
|
103
|
-
Some examples:
|
|
104
|
-
|
|
105
|
-
UNAMBIGUOUS #=> "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"
|
|
106
|
-
# etc...
|
|
107
|
-
tob 255, 16, WORD #=> "FF"
|
|
108
|
-
tob 255, 64, BASE64 #=> "D/"
|
|
109
|
-
|
|
110
|
-
The second way to convert is via a conversion object of `BaseConvert::FromTo`.
|
|
111
|
-
For example, to convert from hexadecimal to octal, and back:
|
|
112
|
-
|
|
113
|
-
h2o = FromTo.new base: 16, to_base: 8
|
|
114
|
-
o2h = FromTo.new base: 8, to_base: 16
|
|
115
|
-
h2o['FFFF'] #=> "177777"
|
|
116
|
-
o2h['177777'] #=> "FFFF"
|
|
117
|
-
|
|
118
|
-
The third way to work with variant base and digits numbers is via the `BaseConvert::Number`:
|
|
119
|
-
|
|
120
|
-
hexadecimal = Number.new('FFFF', base: 16, digits: WORD)
|
|
121
|
-
hexadecimal.to_s #=> "FFFF"
|
|
122
|
-
hexadecimal.to_i #=> 65535
|
|
123
|
-
|
|
124
|
-
# Number will infer your most likely meaning:
|
|
125
|
-
Number.new('FF').to_i #=> 255
|
|
126
|
-
|
|
127
|
-
# But best practice is to fully specify,
|
|
128
|
-
# which is easy to do with keys:
|
|
129
|
-
n = Number.new 'F', base: :hex, digits: :word
|
|
130
|
-
n.to_i #=> 15
|
|
131
|
-
n.to_s #=> "F"
|
|
132
|
-
|
|
133
|
-
# One can make a change of digits:
|
|
134
|
-
n = n.to_digits '0123456789abcdef'
|
|
135
|
-
n.to_s #=> "f"
|
|
136
|
-
n.to_i #=> 15
|
|
137
|
-
|
|
138
|
-
# One can make of change of base:
|
|
139
|
-
n = n.to_base 8
|
|
140
|
-
n.to_s #=> "17"
|
|
141
|
-
|
|
142
|
-
# One can make of change of base and digits:
|
|
143
|
-
n = n.to_base 32, :base64
|
|
144
|
-
# or vice-versa
|
|
145
|
-
n = n.to_digits :base64, 32
|
|
146
|
-
n.to_s #=> "P"
|
|
147
|
-
|
|
148
|
-
## Keys (Symbols)
|
|
187
|
+
Example:
|
|
149
188
|
|
|
150
|
-
|
|
151
|
-
|
|
189
|
+
h2b = BaseConvert::FromTo.new(base: 16, digits: :P95, to_base: 64, to_digits: :B64)
|
|
190
|
+
h2b #=> 16:P95,64:B64
|
|
191
|
+
h2b['FFF'] #=> "//"
|
|
192
|
+
b2h = BaseConvert::FromTo.new(base: 64, digits: :B64, to_base: 16, to_digits: :P95)
|
|
193
|
+
b2h #=> 64:B64,16:P95
|
|
194
|
+
b2h['//'] #=> "FFF"
|
|
152
195
|
|
|
153
|
-
|
|
154
|
-
| -------------- | --------- | ------------- | ----------- |
|
|
155
|
-
| `:g94` | | `G94` | 94 |
|
|
156
|
-
| `:graph` | `:g` | `GRAPH` | 94 |
|
|
157
|
-
| `:qgraph` | `:q` | `QGRAPH` | 91 |
|
|
158
|
-
| `:base64` | `:b64` | `BASE64` | 64 |
|
|
159
|
-
| `:word_` | `:w_` | `WORD_` | 63 |
|
|
160
|
-
| `:word` | `:w` | `WORD` | 62 |
|
|
161
|
-
| `:unambiguous` | `:u` | `UNAMBIGUOUS` | 47 |
|
|
196
|
+
### class Number
|
|
162
197
|
|
|
163
|
-
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
198
|
+
* `new(counter= 0 Integer|String, base: nil Integer|Symbol|String, digits: nil String|Symbol|Integer, validate: true TrueClass|FalseClass) #=> Number`
|
|
199
|
+
* `#base #=> Integer`
|
|
200
|
+
* `#digits #=> String`
|
|
201
|
+
* `#inspect #=> String`
|
|
202
|
+
* `#to_s #=> String`
|
|
203
|
+
* `#to_i #=> Integer`
|
|
204
|
+
* `#to_base(base Integer|Symbol|String, digits=@digits String|Symbol|Integer, validate=@validate TrueClass|FalseClass) #=> Number`
|
|
205
|
+
* `#to_digits(digits String|Symbol|Integer, base=@base Integer|Symbol|String, validate=@validate TrueClass|FalseClass) #=> Number`
|
|
169
206
|
|
|
170
207
|
Example:
|
|
171
208
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
209
|
+
a = BaseConvert::Number.new('FFF', base: 16, digits: :P95)
|
|
210
|
+
a #=> FFF 16:P95
|
|
211
|
+
a.to_i #=> 4095
|
|
212
|
+
b = a.to_digits(:U47)
|
|
213
|
+
b #=> RRR 16:U47
|
|
214
|
+
b.to_i #=> 4095
|
|
215
|
+
c = b.to_base(64, :B64)
|
|
216
|
+
c #=> // 64:B64
|
|
217
|
+
c.to_i #=> 4095
|
|
176
218
|
|
|
177
219
|
## LICENSE:
|
|
178
220
|
|
|
179
221
|
(The MIT License)
|
|
180
222
|
|
|
181
|
-
Copyright (c)
|
|
223
|
+
Copyright (c) 2020 CarlosJHR64
|
|
182
224
|
|
|
183
225
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
184
226
|
a copy of this software and associated documentation files (the
|
data/lib/base_convert.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module BaseConvert
|
|
2
|
-
VERSION = '
|
|
2
|
+
VERSION = '4.0.200111'
|
|
3
3
|
require 'base_convert/base_convert'
|
|
4
|
+
require 'base_convert/chars'
|
|
5
|
+
require 'base_convert/digits'
|
|
6
|
+
require 'base_convert/base'
|
|
4
7
|
require 'base_convert/configuration'
|
|
5
8
|
require 'base_convert/from_to'
|
|
6
9
|
require 'base_convert/number'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module BaseConvert
|
|
2
|
+
class Base < Hash
|
|
3
|
+
alias :get :[]
|
|
4
|
+
def [](key)
|
|
5
|
+
base = super and return base
|
|
6
|
+
case key
|
|
7
|
+
when String
|
|
8
|
+
base = key.length
|
|
9
|
+
when Integer
|
|
10
|
+
base = key
|
|
11
|
+
when /^\D+(\d+)$/
|
|
12
|
+
base = $1.to_i
|
|
13
|
+
else
|
|
14
|
+
begin
|
|
15
|
+
base = DIGITS[key].length
|
|
16
|
+
rescue
|
|
17
|
+
raise 'unrecognized base key'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
raise 'base must be greater than 1' unless base > 1
|
|
21
|
+
base
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# http://rosettacode.org/wiki/Non-decimal_radices/Convert#Ruby
|
|
2
2
|
module BaseConvert
|
|
3
|
-
def toi(string
|
|
3
|
+
def toi(string=to_s, base=@base, digits=@digits)
|
|
4
|
+
return nil if string.empty?
|
|
4
5
|
integer = 0
|
|
5
6
|
string.each_char do |c|
|
|
6
7
|
index = digits.index(c)
|
|
@@ -9,7 +10,8 @@ module BaseConvert
|
|
|
9
10
|
integer
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
def
|
|
13
|
+
def tos(integer=to_i, base=@base, digits=@digits)
|
|
14
|
+
return '' if integer.nil?
|
|
13
15
|
return digits[0] if integer == 0
|
|
14
16
|
string = ''
|
|
15
17
|
while integer > 0
|
|
@@ -19,5 +21,9 @@ module BaseConvert
|
|
|
19
21
|
string
|
|
20
22
|
end
|
|
21
23
|
|
|
24
|
+
def ascii_ordered?(digits=@digits)
|
|
25
|
+
(1..(digits.length-1)).all?{|i|digits[i-1]<digits[i]}
|
|
26
|
+
end
|
|
27
|
+
|
|
22
28
|
extend self
|
|
23
29
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module BaseConvert
|
|
2
|
+
class Chars < Array
|
|
3
|
+
attr_accessor :start,:stop
|
|
4
|
+
def initialize(start=32, stop=126)
|
|
5
|
+
@start,@stop = start,stop
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# i<n>: @start=n.to_i
|
|
9
|
+
# v<n>: @start=n.to_i(16)
|
|
10
|
+
# j<n>: @stop=n.to_i
|
|
11
|
+
# w<n>: @stop=n.to_i(16)
|
|
12
|
+
def set(s)
|
|
13
|
+
t,n = s[0],s[1..-1]
|
|
14
|
+
case t
|
|
15
|
+
when 'i','v'
|
|
16
|
+
@start = n.to_i((t=='v')? 16 : 10)
|
|
17
|
+
when 'j','w'
|
|
18
|
+
@stop = n.to_i((t=='w')? 16 : 10)
|
|
19
|
+
else
|
|
20
|
+
raise 'expected /^([ij]\d+)|([vw]\h+)$/'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def chars_in(x)
|
|
25
|
+
case x
|
|
26
|
+
when Regexp
|
|
27
|
+
@start.upto(@stop).each do |l|
|
|
28
|
+
c = l.chr(Encoding::UTF_8)
|
|
29
|
+
yield c if x.match? c
|
|
30
|
+
end
|
|
31
|
+
when Symbol
|
|
32
|
+
yield x[1..-1].to_i((x[0]=='u')? 16: 10).chr(Encoding::UTF_8)
|
|
33
|
+
when String
|
|
34
|
+
x.chars.each{|c| yield c}
|
|
35
|
+
when Integer
|
|
36
|
+
yield x.chr(Encoding::UTF_8)
|
|
37
|
+
else
|
|
38
|
+
raise "expected Regexp|Symbol|String|Integer, got #{x.class}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def add(x)
|
|
43
|
+
chars_in(x) do |c|
|
|
44
|
+
self.push(c) unless self.include?(c)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def top(x)
|
|
49
|
+
chars_in(x) do |c|
|
|
50
|
+
self.delete(c)
|
|
51
|
+
self.push(c)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def remove(x)
|
|
56
|
+
chars_in(x){|c| self.delete(c)}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -1,61 +1,88 @@
|
|
|
1
1
|
module BaseConvert
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
:
|
|
50
|
-
:
|
|
51
|
-
|
|
52
|
-
:
|
|
53
|
-
|
|
54
|
-
:
|
|
55
|
-
|
|
56
|
-
:
|
|
57
|
-
|
|
58
|
-
:
|
|
59
|
-
|
|
60
|
-
|
|
2
|
+
DIGITS = Digits.new
|
|
3
|
+
|
|
4
|
+
# Naming these letter sequences is inpired by
|
|
5
|
+
# (but not the same as)
|
|
6
|
+
# Unicode character’s General Category.
|
|
7
|
+
DIGITS[:bangs] = '!?'.freeze # Used as method name suffix
|
|
8
|
+
DIGITS[:typers] = '$&@'.freeze # Used as variable name prefix
|
|
9
|
+
DIGITS[:operators] = '*+-/<=>^~'.freeze # Used as mathematical operators
|
|
10
|
+
DIGITS[:separators] = ',.:;|'.freeze # Used to separated items
|
|
11
|
+
DIGITS[:scapes] = '#\\'.freeze # Used to escape what's next
|
|
12
|
+
DIGITS[:groupers] = '()[]{}'.freeze # Used to group items
|
|
13
|
+
DIGITS[:quotes] = %("'`).freeze # Quotes
|
|
14
|
+
DIGITS[:quoters] = %(\%"'`).freeze # Used to quote strings('%' not ASCII ordered)
|
|
15
|
+
DIGITS[:spacers] = '_ '.freeze # 1_000 == 1000 #=> true (Not ASCII ordered)
|
|
16
|
+
DIGITS[:ambiguous] = '012568BDGIOQSZl'.freeze # ASCII ordered ambiguous characters
|
|
17
|
+
|
|
18
|
+
### Recursive string constructors ###
|
|
19
|
+
# 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%"'`_
|
|
20
|
+
DIGITS[:P95] = :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
|
|
21
|
+
INDEXa = DIGITS[:P95].index('a')
|
|
22
|
+
# 0123456789ABCDEF
|
|
23
|
+
DIGITS[:hexadecimal] = DIGITS[:hex] = DIGITS[:h] = :P16
|
|
24
|
+
# 0123456789
|
|
25
|
+
DIGITS[:decimal] = DIGITS[:dec] = :P10
|
|
26
|
+
# 01234567
|
|
27
|
+
DIGITS[:octal] = DIGITS[:oct] = DIGITS[:o] = :P8
|
|
28
|
+
# 01
|
|
29
|
+
DIGITS[:b] = DIGITS[:bin] = DIGITS[:binary] = :P2
|
|
30
|
+
|
|
31
|
+
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
|
32
|
+
DIGITS[:G94] = DIGITS[:g] = :graph
|
|
33
|
+
|
|
34
|
+
# !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~
|
|
35
|
+
DIGITS[:Q91] = DIGITS[:qgraph] = DIGITS[:q] = :'graph-quotes'
|
|
36
|
+
|
|
37
|
+
# ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
|
|
38
|
+
DIGITS[:base64] = DIGITS[:b64] = DIGITS[:B64] = :LN_k43k47
|
|
39
|
+
DIGITS[:letters] = DIGITS[:l] = :B52 # subset of B64
|
|
40
|
+
|
|
41
|
+
# 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz
|
|
42
|
+
DIGITS[:word] = DIGITS[:W63] = :w
|
|
43
|
+
|
|
44
|
+
# 3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz
|
|
45
|
+
DIGITS[:unambiguous] = DIGITS[:U47] = DIGITS[:u] = :'alnum-ambiguous'
|
|
46
|
+
|
|
47
|
+
BASE = Base[
|
|
48
|
+
# 95
|
|
49
|
+
P95: 95,
|
|
50
|
+
print: 95,
|
|
51
|
+
# 94
|
|
52
|
+
G94: 94, g: 94, graph: 94,
|
|
53
|
+
# 91
|
|
54
|
+
Q91: 91, qgraph: 91, q: 91,
|
|
55
|
+
# 64
|
|
56
|
+
B64: 64, base64: 64, b64: 64,
|
|
57
|
+
# 63
|
|
58
|
+
W63: 63, word: 63, w: 63,
|
|
59
|
+
# 52
|
|
60
|
+
letters: 52, l: 52, L: 52,
|
|
61
|
+
# 47
|
|
62
|
+
U47: 47, unambiguous: 47, u: 47,
|
|
63
|
+
# 16
|
|
64
|
+
hexadecimal: 16, hex: 16, h: 16,
|
|
65
|
+
# 15
|
|
66
|
+
ambiguous: 15,
|
|
67
|
+
# 10
|
|
68
|
+
decimal: 10, dec: 10, d: 10,
|
|
69
|
+
# 9
|
|
70
|
+
operators: 9,
|
|
71
|
+
# 8
|
|
72
|
+
octal: 8, oct: 8, o: 8,
|
|
73
|
+
# 6
|
|
74
|
+
groupers: 6,
|
|
75
|
+
# 5
|
|
76
|
+
separators: 5,
|
|
77
|
+
# 4
|
|
78
|
+
quoters: 4,
|
|
79
|
+
# 3
|
|
80
|
+
typers: 3,
|
|
81
|
+
quotes: 3,
|
|
82
|
+
# 2
|
|
83
|
+
binary: 2, bin: 2, b: 2,
|
|
84
|
+
bangs: 2,
|
|
85
|
+
scapes: 2,
|
|
86
|
+
spacers: 2,
|
|
87
|
+
]
|
|
61
88
|
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module BaseConvert
|
|
2
|
+
class Digits < Hash
|
|
3
|
+
alias :get :[]
|
|
4
|
+
def [](key)
|
|
5
|
+
if self.has_key?(key)
|
|
6
|
+
d = super(key)
|
|
7
|
+
return d.is_a?(Symbol)? self[d]: d
|
|
8
|
+
end
|
|
9
|
+
case key
|
|
10
|
+
when Symbol
|
|
11
|
+
chars = Chars.new
|
|
12
|
+
key.to_s.scan(/[+-]?[[:alnum:]]+/).each do |type|
|
|
13
|
+
if self.has_key?(_=type.to_sym)
|
|
14
|
+
chars.add super(_)
|
|
15
|
+
next
|
|
16
|
+
end
|
|
17
|
+
case type
|
|
18
|
+
when /^((u\h+)|(k\d+))+$/
|
|
19
|
+
type.scan(/[uk]\h+/).each{|s| chars.top s.to_sym}
|
|
20
|
+
when /^(([ij]\d+)|([vw]\h+))+$/
|
|
21
|
+
type.scan(/[ijvw]\h+/).each{|s| chars.set s}
|
|
22
|
+
when /^[a-z][a-z]+$/
|
|
23
|
+
chars.add Regexp.new "[[:#{type}:]]"
|
|
24
|
+
when /^[a-z]$/
|
|
25
|
+
chars.add Regexp.new "\\#{type}"
|
|
26
|
+
when /^[A-Z]+$/i
|
|
27
|
+
type.scan(/[A-Z][a-z]*/).each{|property| chars.add /\p{#{property}}/}
|
|
28
|
+
when /^([+-])(\w+)/
|
|
29
|
+
d = self[$2.to_sym]
|
|
30
|
+
case $1
|
|
31
|
+
when '+'
|
|
32
|
+
chars.top d
|
|
33
|
+
when '-'
|
|
34
|
+
chars.remove d
|
|
35
|
+
end
|
|
36
|
+
when /^(\p{L}+)(\d+)$/
|
|
37
|
+
l,m = $1,$2.to_i-1
|
|
38
|
+
n = self.keys.select{|_|_=~/^#{l}\d+$/}.map{|_|_.to_s.sub(l,'').to_i}.max
|
|
39
|
+
raise "no #{l}<n> digits defined" if n.nil?
|
|
40
|
+
raise "out of range of #{l}#{n}" unless m<n
|
|
41
|
+
chars.add self[:"#{l}#{n}"][0..m]
|
|
42
|
+
else
|
|
43
|
+
raise "unrecognized digits key: #{type}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
return chars.uniq.join.freeze
|
|
47
|
+
when String
|
|
48
|
+
digits = nil # set as a side effect...
|
|
49
|
+
unless registry.detect{|_|(digits=self[_]).start_with? key}
|
|
50
|
+
# ...here -------------->^^^^^
|
|
51
|
+
raise 'need at least 2 digits' unless key.length > 1
|
|
52
|
+
raise 'digits must not have duplicates' if key.length > key.chars.uniq.length
|
|
53
|
+
return key
|
|
54
|
+
end
|
|
55
|
+
return digits
|
|
56
|
+
when Integer
|
|
57
|
+
raise 'need digits to cover base' if key > 95
|
|
58
|
+
return self[:P95] # Defined below
|
|
59
|
+
end
|
|
60
|
+
raise 'digits must be String|Symbol|Integer'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def registry(d=nil)
|
|
64
|
+
# BaseConvert::Number memoizes and uses specifically :P95, :B64, and :U47;
|
|
65
|
+
# giving these precedence above the rest.
|
|
66
|
+
@registry ||= [:P95, :B64, :U47, :G94, :Q91, :W63]
|
|
67
|
+
d ? @registry.detect{|_|self[_].start_with? d}: @registry
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def label(d)
|
|
71
|
+
registry(d) or (d[0]+d[1]+d[-2]+d[-1]).to_sym
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def memoize!(keys=registry)
|
|
75
|
+
[*keys].each do |k|
|
|
76
|
+
while s = get(k)
|
|
77
|
+
break if s.is_a? String # links to a constructed String
|
|
78
|
+
raise 'expected Symbol' unless s.is_a? Symbol
|
|
79
|
+
k = s
|
|
80
|
+
end
|
|
81
|
+
self[k]=self[k] if s.nil? # if not memoized, memoize!
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def forget!(keys=registry)
|
|
86
|
+
[*keys].each do |k|
|
|
87
|
+
while s = get(k)
|
|
88
|
+
break if s.is_a? String # links to a constructed String
|
|
89
|
+
raise 'expected Symbol' unless s.is_a? Symbol
|
|
90
|
+
k = s
|
|
91
|
+
end
|
|
92
|
+
self.delete(k) if s.is_a? String
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/base_convert/from_to.rb
CHANGED
|
@@ -2,23 +2,29 @@ module BaseConvert
|
|
|
2
2
|
class FromTo
|
|
3
3
|
include BaseConvert
|
|
4
4
|
|
|
5
|
-
def initialize(base: 10, to_base: base, digits:
|
|
6
|
-
base = BASE[base]
|
|
7
|
-
to_base = BASE[to_base]
|
|
8
|
-
digits = DIGITS[digits]
|
|
9
|
-
to_digits = DIGITS[to_digits]
|
|
10
|
-
raise
|
|
5
|
+
def initialize(base: 10, to_base: base, digits: :P95, to_digits: digits)
|
|
6
|
+
base = BASE[base]
|
|
7
|
+
to_base = BASE[to_base]
|
|
8
|
+
digits = DIGITS[digits]
|
|
9
|
+
to_digits = DIGITS[to_digits]
|
|
10
|
+
raise 'base must cover digits' if base > digits.length or to_base > to_digits.length
|
|
11
11
|
@base, @to_base, @digits, @to_digits = base, to_base, digits, to_digits
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
def inspect
|
|
15
|
+
d0 = DIGITS.label(@digits)
|
|
16
|
+
d1 = DIGITS.label(@to_digits)
|
|
17
|
+
"#{@base}:#{d0},#{@to_base}:#{d1}"
|
|
18
|
+
end
|
|
13
19
|
|
|
14
20
|
def convert(counter)
|
|
15
21
|
case counter
|
|
16
22
|
when Integer
|
|
17
|
-
|
|
23
|
+
tos(counter, @to_base, @to_digits)
|
|
18
24
|
when String
|
|
19
|
-
|
|
25
|
+
tos(toi(counter), @to_base, @to_digits)
|
|
20
26
|
else
|
|
21
|
-
raise
|
|
27
|
+
raise 'counter must be String|Integer'
|
|
22
28
|
end
|
|
23
29
|
end
|
|
24
30
|
alias :[] :convert
|
data/lib/base_convert/number.rb
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
module BaseConvert
|
|
2
2
|
class Number
|
|
3
3
|
include BaseConvert
|
|
4
|
+
DIGITS.memoize!
|
|
4
5
|
|
|
5
6
|
def self.infer(string)
|
|
6
|
-
|
|
7
|
+
p95 = DIGITS[:P95]
|
|
8
|
+
return 2, p95 if string.empty?
|
|
7
9
|
chars = string.chars
|
|
8
|
-
raise '
|
|
9
|
-
max = chars.map{|_|
|
|
10
|
-
return
|
|
11
|
-
return
|
|
12
|
-
return
|
|
13
|
-
return
|
|
14
|
-
return
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return 64,
|
|
20
|
-
|
|
10
|
+
raise 'need digits to cover string' unless chars.all?{|_|p95.include?_}
|
|
11
|
+
max = chars.map{|_|p95.index(_)}.max
|
|
12
|
+
return 95, p95 if max == 94 # string has a space digit.
|
|
13
|
+
return 2, p95 if max < 2
|
|
14
|
+
return 4, p95 if max < 4
|
|
15
|
+
return 8, p95 if max < 8
|
|
16
|
+
return 10, p95 if max < 10
|
|
17
|
+
return 16, p95 if max < 16
|
|
18
|
+
return 32, p95 if max < 32
|
|
19
|
+
u47 = DIGITS[:U47]
|
|
20
|
+
return 47, u47 if chars.all?{|_|u47.include?_}
|
|
21
|
+
return 64, p95 if max < 64
|
|
22
|
+
b64 = DIGITS[:B64]
|
|
23
|
+
return 64, b64 if chars.all?{|_|b64.include?_}
|
|
24
|
+
return 94, p95
|
|
21
25
|
end
|
|
22
26
|
|
|
23
27
|
attr_reader :base, :digits
|
|
@@ -27,65 +31,62 @@ class Number
|
|
|
27
31
|
when true, false
|
|
28
32
|
@validate = validate
|
|
29
33
|
else
|
|
30
|
-
raise
|
|
34
|
+
raise 'validate must be either true or false'
|
|
31
35
|
end
|
|
32
36
|
|
|
33
37
|
# counter
|
|
38
|
+
string = nil
|
|
34
39
|
case counter
|
|
35
40
|
when String
|
|
36
|
-
|
|
41
|
+
string = counter
|
|
37
42
|
base, digits = Number.infer(counter) if base.nil? and digits.nil?
|
|
38
43
|
when Integer
|
|
39
44
|
@integer = counter
|
|
40
|
-
base, digits = 10,
|
|
45
|
+
base, digits = 10, DIGITS[:P95] if base.nil? and digits.nil?
|
|
41
46
|
else
|
|
42
|
-
raise
|
|
47
|
+
raise 'need counter String|Integer'
|
|
43
48
|
end
|
|
44
49
|
|
|
45
50
|
# digits
|
|
46
|
-
|
|
47
|
-
digits = DIGITS[digits]
|
|
48
|
-
raise "Unrecognized digits." if digits.nil?
|
|
49
|
-
end
|
|
50
|
-
digits = DIGITS[base] if digits.nil?
|
|
51
|
-
digits = G94 if digits.nil?
|
|
52
|
-
raise "digits must be a String of at least length 2." unless digits.is_a?(String) and digits.length > 1
|
|
53
|
-
@digits = digits
|
|
51
|
+
@digits = DIGITS[digits || base]
|
|
54
52
|
|
|
55
53
|
# base
|
|
56
|
-
if base.is_a? Symbol
|
|
57
|
-
|
|
58
|
-
raise "Unrecognized base." if base.nil?
|
|
59
|
-
end
|
|
60
|
-
base = @digits.length if base.nil?
|
|
61
|
-
raise "base must be an Integer greater than 1." unless base.is_a?(Integer) and base > 1
|
|
62
|
-
@base = base
|
|
54
|
+
base = digits if base.nil? and digits.is_a? Symbol
|
|
55
|
+
@base = BASE[base || @digits.length]
|
|
63
56
|
|
|
64
57
|
# validate
|
|
65
58
|
if @validate
|
|
66
|
-
raise
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
59
|
+
raise 'digits must cover base' if @base > @digits.length
|
|
60
|
+
unless string.nil? or string.empty?
|
|
61
|
+
indeces = string.chars.map{|_|@digits.index(_)}
|
|
62
|
+
if missing = indeces.any?{|_|_.nil?} or exceeding = indeces.any?{|_|_>=@base}
|
|
63
|
+
if @base <= INDEXa and DIGITS[:P95].start_with?(@digits)
|
|
64
|
+
string = string.upcase
|
|
65
|
+
indeces = string.chars.map{|_|@digits.index(_)}
|
|
66
|
+
missing = indeces.any?{|_|_.nil?} or exceeding = indeces.any?{|_|_>=@base}
|
|
67
|
+
end
|
|
68
|
+
raise 'digits must cover string' if missing
|
|
69
|
+
raise 'digits in string must be under base' if exceeding
|
|
70
|
+
end
|
|
72
71
|
end
|
|
73
72
|
unless @integer.nil?
|
|
74
|
-
raise
|
|
73
|
+
raise 'integer can not be negative' if @integer < 0
|
|
75
74
|
end
|
|
76
75
|
end
|
|
77
76
|
|
|
78
|
-
@integer = toi if @integer.nil?
|
|
79
|
-
|
|
77
|
+
@integer = toi(string) if @integer.nil?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def inspect
|
|
81
|
+
d = DIGITS.label(@digits)
|
|
82
|
+
"#{to_s} #{@base}:#{d}"
|
|
80
83
|
end
|
|
81
84
|
|
|
82
85
|
def validate?
|
|
83
86
|
@validate
|
|
84
87
|
end
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
@string
|
|
88
|
-
end
|
|
89
|
+
alias to_s tos
|
|
89
90
|
|
|
90
91
|
def to_i
|
|
91
92
|
@integer
|
metadata
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: base_convert
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.0.200111
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- carlosjhr64
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-01-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: |
|
|
14
14
|
BaseConvert - Number base conversion.
|
|
15
15
|
|
|
16
16
|
Converts positive integers to different bases:
|
|
17
17
|
Binary, octal, hexadecimal, decimal, or any arbitrary base.
|
|
18
|
-
"Out of the box" handling of up to base
|
|
18
|
+
"Out of the box" handling of up to base 95(:print: characters).
|
|
19
19
|
Allows for arbitrary choice of alphabet(digits).
|
|
20
20
|
email: carlosjhr64@gmail.com
|
|
21
21
|
executables: []
|
|
@@ -24,8 +24,11 @@ extra_rdoc_files: []
|
|
|
24
24
|
files:
|
|
25
25
|
- README.md
|
|
26
26
|
- lib/base_convert.rb
|
|
27
|
+
- lib/base_convert/base.rb
|
|
27
28
|
- lib/base_convert/base_convert.rb
|
|
29
|
+
- lib/base_convert/chars.rb
|
|
28
30
|
- lib/base_convert/configuration.rb
|
|
31
|
+
- lib/base_convert/digits.rb
|
|
29
32
|
- lib/base_convert/from_to.rb
|
|
30
33
|
- lib/base_convert/number.rb
|
|
31
34
|
homepage: https://github.com/carlosjhr64/base_convert
|