base_convert 3.0.191221 → 6.0.210201
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 +208 -127
- data/lib/base_convert.rb +8 -27
- data/lib/base_convert/base.rb +24 -0
- data/lib/base_convert/base_convert.rb +29 -0
- data/lib/base_convert/chars.rb +59 -0
- data/lib/base_convert/configuration.rb +85 -57
- data/lib/base_convert/digits.rb +96 -0
- data/lib/base_convert/from_to.rb +15 -10
- data/lib/base_convert/number.rb +69 -111
- metadata +12 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9e29e85eacc7c4fb82ae72be4dec517de21f2e0c1be03a6dc2670fa1296a9b12
|
|
4
|
+
data.tar.gz: 999da6376a8025b1c5dedd696b5e5c97fb9423b9dfc6f0c59dbefe270dc72dea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 52b687612311825f4bc0877d9e5b4483d58006749dd12ec35ae954864a7b091c5c4a20e796a89aff383a1fe7db331446a13fd575924a1129fe29e78db037c24e
|
|
7
|
+
data.tar.gz: 768e66ca83303a4d4e36c2310291c480923a8a7758a1d18afc67a0c2dee88c8175b65180cb6dbde46cab71095f9a54302cec170da544f65657cc58f1f2ff0a27
|
data/README.md
CHANGED
|
@@ -1,159 +1,240 @@
|
|
|
1
1
|
# BaseConvert
|
|
2
2
|
|
|
3
|
+
* [VERSION 6.0.210201](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
|
|
|
7
|
+
## INSTALL:
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
$ gem install base_convert
|
|
11
|
+
```
|
|
12
|
+
|
|
6
13
|
## DESCRIPTION:
|
|
7
14
|
|
|
8
15
|
BaseConvert - Number base conversion.
|
|
9
16
|
|
|
10
17
|
Converts positive integers to different bases:
|
|
11
18
|
Binary, octal, hexadecimal, decimal, or any arbitrary base.
|
|
12
|
-
"Out of the box" handling of up to base
|
|
19
|
+
"Out of the box" handling of up to base 95(:print: characters).
|
|
13
20
|
Allows for arbitrary choice of alphabet(digits).
|
|
14
21
|
|
|
15
22
|
See also rosettacode.org's [Non-decimal radices convert](http://rosettacode.org/wiki/Non-decimal_radices/Convert).
|
|
16
23
|
|
|
17
24
|
## SYNOPSIS:
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
```ruby
|
|
27
|
+
require 'base_convert'
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
#toi string, base, digits => integer
|
|
30
|
+
BaseConvert.toi 'FF', 16, '0123456789ABCDEF' #=> 255
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
#tos integer, base, digits => string
|
|
33
|
+
BaseConvert.tos 255, 16, '0123456789ABCDEF' #=> "FF"
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
# Number
|
|
32
|
-
n = BaseConvert::Number.new 'FF', base: 16, digits: '0123456789ABCDEF'
|
|
33
|
-
n.to_i #=> 255
|
|
34
|
-
n.to_s #=> "FF"
|
|
35
|
-
#
|
|
36
|
-
n = n.to_base 64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
37
|
-
n.to_s #=> "D/"
|
|
38
|
-
n.to_i #=> 255
|
|
39
|
-
|
|
40
|
-
## INSTALL:
|
|
35
|
+
# FromTo
|
|
36
|
+
c = BaseConvert::FromTo.new base: 16, digits: '0123456789ABCDEF', to_base: 7, to_digits: 'abcdefg'
|
|
37
|
+
c['FFF'] #=> "begea"
|
|
38
|
+
c.inspect #=> "16:P95,7:abfg"
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
# Number
|
|
41
|
+
n = BaseConvert::Number.new 'FF', base: 16, digits: '0123456789ABCDEF'
|
|
42
|
+
n.to_i #=> 255
|
|
43
|
+
n.to_s #=> "FF"
|
|
44
|
+
n.inspect #=> FF 16:P95
|
|
45
|
+
#
|
|
46
|
+
n = n.to_base 64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
47
|
+
n.to_s #=> "D/"
|
|
48
|
+
n.to_i #=> 255
|
|
49
|
+
n.inspect #=> D/ 64:B64
|
|
50
|
+
```
|
|
43
51
|
|
|
44
52
|
## BUT WAIT, THERE'S MORE:
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
* `
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
54
|
+
### module BaseConvert
|
|
55
|
+
|
|
56
|
+
* `#toi(string=to_s String, base=@base Integer, digits=@digits String) #=> Integer`
|
|
57
|
+
* `#tos(integer=to_i Integer, base=@base Integer, digits=@digits String) #=> String`
|
|
58
|
+
* `#ascii_ordered?(digits=@digits String) #=> TrueClass|FalseClass`
|
|
59
|
+
|
|
60
|
+
Exemplar:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
class MyClass
|
|
64
|
+
include BaseConvert
|
|
65
|
+
attr_accessor :to_s, :to_i, :base, :digits
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
obj = MyClass.new
|
|
69
|
+
obj.digits = '!@#$%^&*()'
|
|
70
|
+
obj.base = 10
|
|
71
|
+
|
|
72
|
+
obj.to_s = '@'
|
|
73
|
+
obj.toi #=> 1
|
|
74
|
+
|
|
75
|
+
obj.to_i = 3
|
|
76
|
+
obj.tos #=> "$"
|
|
77
|
+
|
|
78
|
+
obj.ascii_ordered? #=> false
|
|
79
|
+
obj.digits = 'ABCDEFGHIJKLMNOP'
|
|
80
|
+
obj.ascii_ordered? #=> true
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Hash DIGITS
|
|
84
|
+
|
|
85
|
+
#### DIGITS methods
|
|
86
|
+
|
|
87
|
+
* `DIGITS.get(key Symbol) #=> String|Symbol|NilClass`
|
|
88
|
+
* `DIGITS.registry(digits=nil NilClass|String) #=> Array(Symbol)|Symbol`
|
|
89
|
+
* `DIGITS.label(digits String) #=> String`
|
|
90
|
+
* `DIGITS.memoize!(key=registry Symbol|Array(Symbol))`
|
|
91
|
+
* `DIGITS.forget!(key=registry Symbol|Array(Symbol))`
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
Exemplar:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
include BaseConvert
|
|
98
|
+
DIGITS.get(:P95) #=> :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
|
|
99
|
+
DIGITS[:P95]
|
|
100
|
+
#=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%\"'`_ "
|
|
101
|
+
DIGITS.registry #=> [:P95, :B64, :U47, :G94, :Q91, :W63]
|
|
102
|
+
DIGITS.registry('347') #=> :U47
|
|
103
|
+
DIGITS.registry('0') #=> :P95
|
|
104
|
+
DIGITS.registry('AB') #=> :B64
|
|
105
|
+
DIGITS.registry('Cukoe') #=> nil
|
|
106
|
+
DIGITS.label('Cukoe') #=> :Cuoe
|
|
107
|
+
DIGITS.label('AaBbCcXxYyZz') #=> :AaZz
|
|
108
|
+
DIGITS[:N] #=> "0123456789"
|
|
109
|
+
DIGITS.get(:N) #=> nil
|
|
110
|
+
DIGITS.memoize!(:N)
|
|
111
|
+
DIGITS.get(:N) #=> "0123456789"
|
|
112
|
+
DIGITS.forget!(:N)
|
|
113
|
+
DIGITS.get(:N) #=> nil
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
#### DIGITS constructions
|
|
118
|
+
|
|
119
|
+
`BaseConvert::DIGITS` will take a `Symbol` representation of `Regexp` patterns.
|
|
120
|
+
See [Ruby-Doc's Regexp](https://ruby-doc.org/core-2.7.0/Regexp.html) documentation
|
|
121
|
+
for a full list of keys. The following provides an exemplar survey:
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
# Character Classes
|
|
125
|
+
# Selected from ASCII 32..126
|
|
126
|
+
DIGITS[:w] #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
|
|
127
|
+
DIGITS[:d] #=> "0123456789"
|
|
128
|
+
# Note: :h was overridden, see :xdigit.
|
|
129
|
+
DIGITS[:h] #=> "0123456789ABCDEF"
|
|
130
|
+
DIGITS[:alpha] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
131
|
+
DIGITS[:graph]
|
|
132
|
+
#=> "!\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
133
|
+
DIGITS[:lower] #=> "abcdefghijklmnopqrstuvwxyz"
|
|
134
|
+
DIGITS[:punct] #=> "!\"\#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
|
135
|
+
DIGITS[:upper] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
136
|
+
DIGITS[:xdigit] #=> "0123456789ABCDEFabcdef"
|
|
137
|
+
|
|
138
|
+
# Character Properties
|
|
139
|
+
# Selected from ASCII 32..126
|
|
140
|
+
DIGITS[:Alnum] #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
141
|
+
DIGITS[:Any]
|
|
142
|
+
#=> " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
143
|
+
|
|
144
|
+
# General Category
|
|
145
|
+
# Selected from ASCII 32..126
|
|
146
|
+
DIGITS[:Ps] #=> "([{"
|
|
147
|
+
DIGITS[:Pe] #=> ")]}"
|
|
148
|
+
DIGITS[:S] #=> "$+<=>^`|~"
|
|
149
|
+
|
|
150
|
+
# Ranged Selections
|
|
151
|
+
# v<hex>w<hex>_<filter>
|
|
152
|
+
DIGITS[:v1d7d8w1d7e1_Any] #=> "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡"
|
|
153
|
+
# i<dec>j<dec>_<filter>
|
|
154
|
+
DIGITS[:i120488j120513_Any] #=> "𝚨𝚩𝚪𝚫𝚬𝚭𝚮𝚯𝚰𝚱𝚲𝚳𝚴𝚵𝚶𝚷𝚸𝚹𝚺𝚻𝚼𝚽𝚾𝚿𝛀𝛁"
|
|
155
|
+
|
|
156
|
+
# Specified Characters
|
|
157
|
+
# u<hex>
|
|
158
|
+
DIGITS[:u61u62] #=> "ab"
|
|
159
|
+
# k<dec>
|
|
160
|
+
DIGITS[:k97k98] #=> "ab"
|
|
161
|
+
|
|
162
|
+
# BaseConvert's Custom Sets
|
|
163
|
+
DIGITS[:bangs] #=> "!?"
|
|
164
|
+
DIGITS[:typers] #=> "$&@"
|
|
165
|
+
DIGITS[:operators] #=> "*+-/<=>^~"
|
|
166
|
+
DIGITS[:separators] #=> ",.:;|"
|
|
167
|
+
DIGITS[:scapes] #=> "#\\"
|
|
168
|
+
DIGITS[:groupers] #=> "()[]{}"
|
|
169
|
+
DIGITS[:quotes] #=> "\"'`"
|
|
170
|
+
DIGITS[:quoters] #=> "%\"'`"
|
|
171
|
+
DIGITS[:spacers] #=> "_ "
|
|
172
|
+
DIGITS[:ambiguous] #=> "012568BDGIOQSZl"
|
|
173
|
+
|
|
174
|
+
# Composition, add merge:
|
|
175
|
+
DIGITS[:d_ambiguous] #=> "0123456789BDGIOQSZl"
|
|
176
|
+
# Composition, add top:
|
|
177
|
+
DIGITS[:'d+ambiguous'] #=> "3479012568BDGIOQSZl"
|
|
178
|
+
# Composition, subtract:
|
|
179
|
+
DIGITS[:'d-ambiguous'] #=> "3479"
|
|
180
|
+
|
|
181
|
+
# Compositions used in BaseConvert
|
|
182
|
+
# :P95 is:
|
|
183
|
+
DIGITS[:alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers]
|
|
184
|
+
#=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%\"'`_ "
|
|
185
|
+
# :B64 is:
|
|
186
|
+
DIGITS[:LN_k43k47] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
187
|
+
# :U47 is:
|
|
188
|
+
DIGITS[:'alnum-ambiguous'] #=> "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### class FromTo
|
|
192
|
+
|
|
193
|
+
* `new(base: 10 Integer|Symbol|String, to_base: base, digits: :P95 String|Symbol|Integer, to_digits: digits) #=> FromTo`
|
|
194
|
+
* `#inspect #=> String`
|
|
195
|
+
* `#convert(counter String|Integer) #=> String`
|
|
196
|
+
|
|
197
|
+
Example:
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
h2b = BaseConvert::FromTo.new(base: 16, digits: :P95, to_base: 64, to_digits: :B64)
|
|
201
|
+
h2b #=> 16:P95,64:B64
|
|
202
|
+
h2b['FFF'] #=> "//"
|
|
203
|
+
b2h = BaseConvert::FromTo.new(base: 64, digits: :B64, to_base: 16, to_digits: :P95)
|
|
204
|
+
b2h #=> 64:B64,16:P95
|
|
205
|
+
b2h['//'] #=> "FFF"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### class Number
|
|
209
|
+
|
|
210
|
+
* `new(counter= 0 Integer|String, base: nil Integer|Symbol|String, digits: nil String|Symbol|Integer, validate: true TrueClass|FalseClass) #=> Number`
|
|
211
|
+
* `#base #=> Integer`
|
|
212
|
+
* `#digits #=> String`
|
|
213
|
+
* `#inspect #=> String`
|
|
214
|
+
* `#to_s #=> String`
|
|
215
|
+
* `#to_i #=> Integer`
|
|
216
|
+
* `#to_base(base Integer|Symbol|String, digits=@digits String|Symbol|Integer, validate=@validate TrueClass|FalseClass) #=> Number`
|
|
217
|
+
* `#to_digits(digits String|Symbol|Integer, base=@base Integer|Symbol|String, validate=@validate TrueClass|FalseClass) #=> Number`
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
a = BaseConvert::Number.new('FFF', base: 16, digits: :P95)
|
|
223
|
+
a #=> FFF 16:P95
|
|
224
|
+
a.to_i #=> 4095
|
|
225
|
+
b = a.to_digits(:U47)
|
|
226
|
+
b #=> RRR 16:U47
|
|
227
|
+
b.to_i #=> 4095
|
|
228
|
+
c = b.to_base(64, :B64)
|
|
229
|
+
c #=> // 64:B64
|
|
230
|
+
c.to_i #=> 4095
|
|
231
|
+
```
|
|
151
232
|
|
|
152
233
|
## LICENSE:
|
|
153
234
|
|
|
154
235
|
(The MIT License)
|
|
155
236
|
|
|
156
|
-
Copyright (c)
|
|
237
|
+
Copyright (c) 2021 CarlosJHR64
|
|
157
238
|
|
|
158
239
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
159
240
|
a copy of this software and associated documentation files (the
|
data/lib/base_convert.rb
CHANGED
|
@@ -1,30 +1,11 @@
|
|
|
1
|
-
# http://rosettacode.org/wiki/Non-decimal_radices/Convert#Ruby
|
|
2
1
|
module BaseConvert
|
|
3
|
-
VERSION = '
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
integer
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def tob(integer=@integer, base=@base, digits=@digits)
|
|
15
|
-
return digits[0] if integer == 0
|
|
16
|
-
string = ''
|
|
17
|
-
while integer > 0
|
|
18
|
-
integer, index = integer.divmod(base)
|
|
19
|
-
string = string.insert(0, digits[index])
|
|
20
|
-
end
|
|
21
|
-
string
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
extend self
|
|
25
|
-
|
|
26
|
-
autoload :Configuration, 'base_convert/configuration'
|
|
27
|
-
autoload :FromTo, 'base_convert/from_to'
|
|
28
|
-
autoload :Number, 'base_convert/number'
|
|
2
|
+
VERSION = '6.0.210201'
|
|
3
|
+
require 'base_convert/base_convert'
|
|
4
|
+
require 'base_convert/chars'
|
|
5
|
+
require 'base_convert/digits'
|
|
6
|
+
require 'base_convert/base'
|
|
7
|
+
require 'base_convert/configuration'
|
|
8
|
+
require 'base_convert/from_to'
|
|
9
|
+
require 'base_convert/number'
|
|
29
10
|
end
|
|
30
11
|
#`ruby`
|
|
@@ -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
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# http://rosettacode.org/wiki/Non-decimal_radices/Convert#Ruby
|
|
2
|
+
module BaseConvert
|
|
3
|
+
def toi(string=to_s, base=@base, digits=@digits)
|
|
4
|
+
return nil if string.empty?
|
|
5
|
+
integer = 0
|
|
6
|
+
string.each_char do |c|
|
|
7
|
+
index = digits.index(c)
|
|
8
|
+
integer = integer * base + index
|
|
9
|
+
end
|
|
10
|
+
integer
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def tos(integer=to_i, base=@base, digits=@digits)
|
|
14
|
+
return '' if integer.nil?
|
|
15
|
+
return digits[0] if integer == 0
|
|
16
|
+
string = ''
|
|
17
|
+
while integer > 0
|
|
18
|
+
integer, index = integer.divmod(base)
|
|
19
|
+
string = string.prepend digits[index]
|
|
20
|
+
end
|
|
21
|
+
string
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def ascii_ordered?(digits=@digits)
|
|
25
|
+
(1..(digits.length-1)).all?{|i|digits[i-1]<digits[i]}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
extend self
|
|
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,60 +1,88 @@
|
|
|
1
1
|
module BaseConvert
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
GRAPH = 0.upto(255).map{|i| i.chr}.select{|c| c=~/[[:graph:]]/}.join.freeze
|
|
5
|
-
QGRAPH = GRAPH.delete(%('"`)).freeze
|
|
6
|
-
|
|
7
|
-
WORD_ = 0.upto(255).map{|i| i.chr}.select{|c| c=~/\w/}.join.freeze
|
|
8
|
-
WORD = WORD_.delete('_').freeze
|
|
9
|
-
INDEXa = WORD.index('a')
|
|
10
|
-
|
|
11
|
-
AMBIGUOUS = 'B8G6I1l0OQDS5Z2'.freeze
|
|
12
|
-
UNAMBIGUOUS = WORD.delete(AMBIGUOUS).freeze
|
|
13
|
-
|
|
14
|
-
BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
|
15
|
-
|
|
16
|
-
BASE = {
|
|
17
|
-
:graph => GRAPH.length,
|
|
18
|
-
:qgraph => QGRAPH.length,
|
|
19
|
-
:word_ => WORD_.length,
|
|
20
|
-
:word => WORD.length,
|
|
21
|
-
:unambiguous => UNAMBIGUOUS.length,
|
|
22
|
-
:base64 => 64,
|
|
23
|
-
:b64 => 64,
|
|
24
|
-
:hexadecimal => 16,
|
|
25
|
-
:hex => 16,
|
|
26
|
-
:h => 16,
|
|
27
|
-
:decimal => 10,
|
|
28
|
-
:dec => 10,
|
|
29
|
-
:d => 10,
|
|
30
|
-
:octal => 8,
|
|
31
|
-
:oct => 8,
|
|
32
|
-
:o => 8,
|
|
33
|
-
:binary => 2,
|
|
34
|
-
:bin => 2,
|
|
35
|
-
:b => 2,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
BASE[:g] = BASE[:graph]
|
|
39
|
-
BASE[:q] = BASE[:qgraph]
|
|
40
|
-
BASE[:w_] = BASE[:word_]
|
|
41
|
-
BASE[:w] = BASE[:word]
|
|
42
|
-
BASE[:u] = BASE[:unambiguous]
|
|
43
|
-
|
|
44
|
-
DIGITS = {
|
|
45
|
-
:graph => GRAPH,
|
|
46
|
-
:g => GRAPH,
|
|
47
|
-
:qgraph => QGRAPH,
|
|
48
|
-
:q => QGRAPH,
|
|
49
|
-
:word_ => WORD_,
|
|
50
|
-
:w_ => WORD_,
|
|
51
|
-
:word => WORD,
|
|
52
|
-
:w => WORD,
|
|
53
|
-
:unambiguous => UNAMBIGUOUS,
|
|
54
|
-
:u => UNAMBIGUOUS,
|
|
55
|
-
:base64 => BASE64,
|
|
56
|
-
:b64 => BASE64,
|
|
57
|
-
}
|
|
2
|
+
DIGITS = Digits.new
|
|
58
3
|
|
|
59
|
-
|
|
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
|
+
]
|
|
60
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 in configuration.rb
|
|
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. Defined in configuration.rb.
|
|
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
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
module BaseConvert
|
|
2
2
|
class FromTo
|
|
3
|
-
include Configuration
|
|
4
3
|
include BaseConvert
|
|
5
4
|
|
|
6
|
-
def initialize(base: 10, to_base: base, digits:
|
|
7
|
-
base = BASE[base]
|
|
8
|
-
to_base = BASE[to_base]
|
|
9
|
-
digits = DIGITS[digits]
|
|
10
|
-
to_digits = DIGITS[to_digits]
|
|
11
|
-
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
|
|
12
11
|
@base, @to_base, @digits, @to_digits = base, to_base, digits, to_digits
|
|
13
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
|
|
14
19
|
|
|
15
20
|
def convert(counter)
|
|
16
21
|
case counter
|
|
17
22
|
when Integer
|
|
18
|
-
|
|
23
|
+
tos(counter, @to_base, @to_digits)
|
|
19
24
|
when String
|
|
20
|
-
|
|
25
|
+
tos(toi(counter), @to_base, @to_digits)
|
|
21
26
|
else
|
|
22
|
-
raise
|
|
27
|
+
raise 'counter must be String|Integer'
|
|
23
28
|
end
|
|
24
29
|
end
|
|
25
30
|
alias :[] :convert
|
data/lib/base_convert/number.rb
CHANGED
|
@@ -1,140 +1,98 @@
|
|
|
1
1
|
module BaseConvert
|
|
2
2
|
class Number
|
|
3
|
-
include Configuration
|
|
4
3
|
include BaseConvert
|
|
4
|
+
DIGITS.memoize!
|
|
5
5
|
|
|
6
|
-
def
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
def self.infer(string)
|
|
7
|
+
p95 = DIGITS[:P95]
|
|
8
|
+
return 2, p95 if string.empty?
|
|
9
|
+
chars = string.chars
|
|
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
|
|
14
25
|
end
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return 8 if min <= 8
|
|
25
|
-
return 16 if min <= 16
|
|
26
|
-
return 32
|
|
27
|
-
end
|
|
28
|
-
when UNAMBIGUOUS
|
|
29
|
-
if min <= 22
|
|
30
|
-
raise "Need base for UNAMBIGUOUS." if @string.length < 8
|
|
31
|
-
return 22
|
|
32
|
-
end
|
|
33
|
-
when QGRAPH, GRAPH
|
|
34
|
-
n = @digits.index 'a'
|
|
35
|
-
if min <= n
|
|
36
|
-
raise "Need base for QGRAPH or GRAPH." if @string.length < 8
|
|
37
|
-
return n
|
|
38
|
-
end
|
|
27
|
+
attr_reader :base, :digits
|
|
28
|
+
def initialize(counter=0, base: nil, digits: nil, validate: true)
|
|
29
|
+
# validate
|
|
30
|
+
case validate
|
|
31
|
+
when true, false
|
|
32
|
+
@validate = validate
|
|
33
|
+
else
|
|
34
|
+
raise 'validate must be either true or false'
|
|
39
35
|
end
|
|
40
|
-
return max
|
|
41
|
-
end
|
|
42
36
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@digits = GRAPH
|
|
53
|
-
else
|
|
54
|
-
raise "Need digits that can cover base #{@base}."
|
|
55
|
-
end
|
|
56
|
-
end
|
|
37
|
+
# counter
|
|
38
|
+
string = nil
|
|
39
|
+
case counter
|
|
40
|
+
when String
|
|
41
|
+
string = counter
|
|
42
|
+
base, digits = Number.infer(counter) if base.nil? and digits.nil?
|
|
43
|
+
when Integer
|
|
44
|
+
@integer = counter
|
|
45
|
+
base, digits = 10, DIGITS[:P95] if base.nil? and digits.nil?
|
|
57
46
|
else
|
|
58
|
-
|
|
59
|
-
digits = DIGITS[@digits]
|
|
60
|
-
raise "Unrecognized digits #{@digits}." if digits.nil?
|
|
61
|
-
@digits = digits
|
|
62
|
-
else
|
|
63
|
-
raise "digits must be a String of at least length 2." unless @digits.is_a?(String) and @digits.length > 2
|
|
64
|
-
end
|
|
47
|
+
raise 'need counter String|Integer'
|
|
65
48
|
end
|
|
66
|
-
end
|
|
67
49
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
50
|
+
# digits
|
|
51
|
+
@digits = DIGITS[digits || base]
|
|
52
|
+
|
|
53
|
+
# base
|
|
54
|
+
base = digits if base.nil? and digits.is_a? Symbol
|
|
55
|
+
@base = BASE[base || @digits.length]
|
|
56
|
+
|
|
57
|
+
# validate
|
|
58
|
+
if @validate
|
|
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
|
|
75
71
|
end
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
base = BASE[@base]
|
|
79
|
-
raise "Unrecognized base #{@base}." if base.nil?
|
|
80
|
-
@base = base
|
|
81
|
-
else
|
|
82
|
-
raise "base must be an Integer greater than 1." unless @base.is_a?(Integer) and @base > 1
|
|
72
|
+
unless @integer.nil?
|
|
73
|
+
raise 'integer can not be negative' if @integer < 0
|
|
83
74
|
end
|
|
84
|
-
_digits!
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def _validate
|
|
89
|
-
raise "digits must cover base." if @base > @digits.length
|
|
90
|
-
raise "digits must not have duplicates." if @digits.length > @digits.chars.uniq.length
|
|
91
|
-
unless @string.nil?
|
|
92
|
-
raise "digits must cover string." unless @string.chars.all?{|_|@digits.include?_}
|
|
93
|
-
raise "digits in string must be under base." unless @base > @digits.index(@string.chars.max)
|
|
94
75
|
end
|
|
95
|
-
unless @integer.nil?
|
|
96
|
-
raise "integer can't be negative." if @integer < 0
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
76
|
|
|
100
|
-
|
|
101
|
-
_base!
|
|
102
|
-
@string.upcase! if @base <= INDEXa and @digits == WORD
|
|
103
|
-
_validate if @validate
|
|
104
|
-
@integer = toi
|
|
77
|
+
@integer = toi(string) if @integer.nil?
|
|
105
78
|
end
|
|
106
79
|
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
@string = tob
|
|
80
|
+
def inspect
|
|
81
|
+
d = DIGITS.label(@digits)
|
|
82
|
+
"#{to_s} #{@base}:#{d}"
|
|
111
83
|
end
|
|
112
84
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
@base, @digits, @validate = base, digits, validate
|
|
116
|
-
@string, @integer = nil, nil
|
|
117
|
-
case counter
|
|
118
|
-
when String
|
|
119
|
-
@string = counter
|
|
120
|
-
_integer!
|
|
121
|
-
when Integer
|
|
122
|
-
@integer = counter
|
|
123
|
-
_string!
|
|
124
|
-
else
|
|
125
|
-
raise "Need counter String|Integer."
|
|
126
|
-
end
|
|
85
|
+
def validate?
|
|
86
|
+
@validate
|
|
127
87
|
end
|
|
128
88
|
|
|
129
|
-
|
|
130
|
-
@string
|
|
131
|
-
end
|
|
89
|
+
alias to_s tos
|
|
132
90
|
|
|
133
91
|
def to_i
|
|
134
92
|
@integer
|
|
135
93
|
end
|
|
136
94
|
|
|
137
|
-
def to_base(base, digits
|
|
95
|
+
def to_base(base, digits=(base.is_a?Symbol)? DIGITS[base] : @digits, validate=@validate)
|
|
138
96
|
Number.new @integer, base: base, digits: digits, validate: validate
|
|
139
97
|
end
|
|
140
98
|
|
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: 6.0.210201
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- carlosjhr64
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-02-01 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,14 +24,18 @@ extra_rdoc_files: []
|
|
|
24
24
|
files:
|
|
25
25
|
- README.md
|
|
26
26
|
- lib/base_convert.rb
|
|
27
|
+
- lib/base_convert/base.rb
|
|
28
|
+
- lib/base_convert/base_convert.rb
|
|
29
|
+
- lib/base_convert/chars.rb
|
|
27
30
|
- lib/base_convert/configuration.rb
|
|
31
|
+
- lib/base_convert/digits.rb
|
|
28
32
|
- lib/base_convert/from_to.rb
|
|
29
33
|
- lib/base_convert/number.rb
|
|
30
34
|
homepage: https://github.com/carlosjhr64/base_convert
|
|
31
35
|
licenses:
|
|
32
36
|
- MIT
|
|
33
37
|
metadata: {}
|
|
34
|
-
post_install_message:
|
|
38
|
+
post_install_message:
|
|
35
39
|
rdoc_options: []
|
|
36
40
|
require_paths:
|
|
37
41
|
- lib
|
|
@@ -46,9 +50,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
46
50
|
- !ruby/object:Gem::Version
|
|
47
51
|
version: '0'
|
|
48
52
|
requirements:
|
|
49
|
-
- 'ruby: ruby
|
|
50
|
-
rubygems_version: 3.
|
|
51
|
-
signing_key:
|
|
53
|
+
- 'ruby: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]'
|
|
54
|
+
rubygems_version: 3.2.3
|
|
55
|
+
signing_key:
|
|
52
56
|
specification_version: 4
|
|
53
57
|
summary: BaseConvert - Number base conversion.
|
|
54
58
|
test_files: []
|