base_convert 6.0.210201 → 7.0.221226
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +57 -70
- data/lib/base_convert/base.rb +60 -19
- data/lib/base_convert/chars.rb +18 -26
- data/lib/base_convert/digits.rb +116 -78
- data/lib/base_convert/from_to.rb +1 -1
- data/lib/base_convert/{base_convert.rb → methods.rb} +5 -8
- data/lib/base_convert/number.rb +17 -25
- data/lib/base_convert.rb +7 -8
- metadata +9 -10
- data/lib/base_convert/configuration.rb +0 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0468363560e386197373265ab15994e9f75b97965f01fd7c7d039ba659fb9e5d'
|
4
|
+
data.tar.gz: e22bdb75673cb9e2bedc6edd7c7dd1349234ff8709b77b7e1159e74b79b37975
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dfa9704f01b5145bdb9ad4070d59aa4027dafcb8431fd24c42134d861475f33c97a3db30549c606dffd60acdca15768211abac2b648ee6de147481038f405cc
|
7
|
+
data.tar.gz: '0948eea3537cc52a521d633c68aa6a4121646bfe20af41e3d11ca902a8cb3f814468ad022c8b5879726de4c24bf4433dbb88b9fc690f53d03d33a0a4bc0c1e52'
|
data/README.md
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
# BaseConvert
|
2
2
|
|
3
|
-
* [VERSION
|
3
|
+
* [VERSION 7.0.221226](https://github.com/carlosjhr64/base_convert/releases)
|
4
4
|
* [github](https://www.github.com/carlosjhr64/base_convert)
|
5
5
|
* [rubygems](https://rubygems.org/gems/base_convert)
|
6
6
|
|
7
7
|
## INSTALL:
|
8
|
-
|
9
8
|
```shell
|
10
9
|
$ gem install base_convert
|
11
10
|
```
|
12
|
-
|
13
11
|
## DESCRIPTION:
|
14
12
|
|
15
13
|
BaseConvert - Number base conversion.
|
@@ -19,49 +17,45 @@ Binary, octal, hexadecimal, decimal, or any arbitrary base.
|
|
19
17
|
"Out of the box" handling of up to base 95(:print: characters).
|
20
18
|
Allows for arbitrary choice of alphabet(digits).
|
21
19
|
|
22
|
-
See also rosettacode.org's [Non-decimal radices convert](http://rosettacode.org/wiki/Non-decimal_radices/Convert).
|
23
|
-
|
24
20
|
## SYNOPSIS:
|
25
|
-
|
26
21
|
```ruby
|
27
22
|
require 'base_convert'
|
28
23
|
|
29
24
|
#toi string, base, digits => integer
|
30
|
-
BaseConvert.toi 'FF', 16, '0123456789ABCDEF' #=> 255
|
25
|
+
BaseConvert::Methods.toi 'FF', 16, '0123456789ABCDEF' #=> 255
|
31
26
|
|
32
27
|
#tos integer, base, digits => string
|
33
|
-
BaseConvert.tos 255, 16, '0123456789ABCDEF' #=> "FF"
|
28
|
+
BaseConvert::Methods.tos 255, 16, '0123456789ABCDEF' #=> "FF"
|
34
29
|
|
35
30
|
# FromTo
|
36
|
-
c = BaseConvert::FromTo.new base:
|
37
|
-
|
38
|
-
c
|
31
|
+
c = BaseConvert::FromTo.new base: 16, digits: '0123456789ABCDEF',
|
32
|
+
to_base: 7, to_digits: 'abcdefg'
|
33
|
+
c['FFF'] #=> "begea"
|
34
|
+
c.inspect #=> "16:P95,7:abfg"
|
39
35
|
|
40
36
|
# Number
|
41
37
|
n = BaseConvert::Number.new 'FF', base: 16, digits: '0123456789ABCDEF'
|
42
|
-
n.to_i
|
43
|
-
n.to_s
|
38
|
+
n.to_i #=> 255
|
39
|
+
n.to_s #=> "FF"
|
44
40
|
n.inspect #=> FF 16:P95
|
45
41
|
#
|
46
42
|
n = n.to_base 64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
47
|
-
n.to_s
|
48
|
-
n.to_i
|
43
|
+
n.to_s #=> "D/"
|
44
|
+
n.to_i #=> 255
|
49
45
|
n.inspect #=> D/ 64:B64
|
50
46
|
```
|
51
|
-
|
52
47
|
## BUT WAIT, THERE'S MORE:
|
53
48
|
|
54
|
-
### module BaseConvert
|
49
|
+
### module BaseConvert::Methods
|
55
50
|
|
56
51
|
* `#toi(string=to_s String, base=@base Integer, digits=@digits String) #=> Integer`
|
57
52
|
* `#tos(integer=to_i Integer, base=@base Integer, digits=@digits String) #=> String`
|
58
|
-
* `#
|
53
|
+
* `#chars_ordered?(digits=@digits String) #=> TrueClass|FalseClass`
|
59
54
|
|
60
55
|
Exemplar:
|
61
|
-
|
62
56
|
```ruby
|
63
57
|
class MyClass
|
64
|
-
include BaseConvert
|
58
|
+
include BaseConvert::Methods
|
65
59
|
attr_accessor :to_s, :to_i, :base, :digits
|
66
60
|
end
|
67
61
|
|
@@ -75,12 +69,11 @@ obj.toi #=> 1
|
|
75
69
|
obj.to_i = 3
|
76
70
|
obj.tos #=> "$"
|
77
71
|
|
78
|
-
obj.
|
72
|
+
obj.chars_ordered? #=> false
|
79
73
|
obj.digits = 'ABCDEFGHIJKLMNOP'
|
80
|
-
obj.
|
74
|
+
obj.chars_ordered? #=> true
|
81
75
|
```
|
82
|
-
|
83
|
-
### Hash DIGITS
|
76
|
+
### BaseConvert::DIGITS < Hash
|
84
77
|
|
85
78
|
#### DIGITS methods
|
86
79
|
|
@@ -90,54 +83,51 @@ obj.ascii_ordered? #=> true
|
|
90
83
|
* `DIGITS.memoize!(key=registry Symbol|Array(Symbol))`
|
91
84
|
* `DIGITS.forget!(key=registry Symbol|Array(Symbol))`
|
92
85
|
|
93
|
-
|
94
86
|
Exemplar:
|
95
|
-
|
96
87
|
```ruby
|
97
88
|
include BaseConvert
|
98
|
-
DIGITS.get(:P95)
|
89
|
+
DIGITS.get(:P95)
|
90
|
+
#=> :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
|
99
91
|
DIGITS[:P95]
|
100
92
|
#=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%\"'`_ "
|
101
|
-
DIGITS.registry
|
102
|
-
DIGITS.registry('347')
|
103
|
-
DIGITS.registry('0')
|
104
|
-
DIGITS.registry('AB')
|
105
|
-
DIGITS.registry('Cukoe')
|
106
|
-
DIGITS.label('Cukoe')
|
93
|
+
DIGITS.registry #=> [:P95, :B64, :U47, :G94, :Q91, :W63]
|
94
|
+
DIGITS.registry('347') #=> :U47
|
95
|
+
DIGITS.registry('0') #=> :P95
|
96
|
+
DIGITS.registry('AB') #=> :B64
|
97
|
+
DIGITS.registry('Cukoe') #=> nil
|
98
|
+
DIGITS.label('Cukoe') #=> :Cuoe
|
107
99
|
DIGITS.label('AaBbCcXxYyZz') #=> :AaZz
|
108
|
-
DIGITS[:N]
|
109
|
-
DIGITS.get(:N)
|
100
|
+
DIGITS[:N] #=> "0123456789"
|
101
|
+
DIGITS.get(:N) #=> nil
|
110
102
|
DIGITS.memoize!(:N)
|
111
|
-
DIGITS.get(:N)
|
103
|
+
DIGITS.get(:N) #=> "0123456789"
|
112
104
|
DIGITS.forget!(:N)
|
113
|
-
DIGITS.get(:N)
|
105
|
+
DIGITS.get(:N) #=> nil
|
114
106
|
```
|
115
|
-
|
116
|
-
|
117
107
|
#### DIGITS constructions
|
118
108
|
|
119
109
|
`BaseConvert::DIGITS` will take a `Symbol` representation of `Regexp` patterns.
|
120
110
|
See [Ruby-Doc's Regexp](https://ruby-doc.org/core-2.7.0/Regexp.html) documentation
|
121
111
|
for a full list of keys. The following provides an exemplar survey:
|
122
|
-
|
123
112
|
```ruby
|
124
113
|
# Character Classes
|
125
114
|
# Selected from ASCII 32..126
|
126
115
|
DIGITS[:w] #=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
|
127
116
|
DIGITS[:d] #=> "0123456789"
|
128
117
|
# Note: :h was overridden, see :xdigit.
|
129
|
-
DIGITS[:h]
|
118
|
+
DIGITS[:h] #=> "0123456789ABCDEF"
|
130
119
|
DIGITS[:alpha] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
131
120
|
DIGITS[:graph]
|
132
121
|
#=> "!\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
133
|
-
DIGITS[:lower]
|
134
|
-
DIGITS[:punct]
|
135
|
-
DIGITS[:upper]
|
122
|
+
DIGITS[:lower] #=> "abcdefghijklmnopqrstuvwxyz"
|
123
|
+
DIGITS[:punct] #=> "!\"\#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
124
|
+
DIGITS[:upper] #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
136
125
|
DIGITS[:xdigit] #=> "0123456789ABCDEFabcdef"
|
137
126
|
|
138
127
|
# Character Properties
|
139
128
|
# Selected from ASCII 32..126
|
140
|
-
DIGITS[:Alnum]
|
129
|
+
DIGITS[:Alnum]
|
130
|
+
#=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
141
131
|
DIGITS[:Any]
|
142
132
|
#=> " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
143
133
|
|
@@ -149,7 +139,7 @@ DIGITS[:S] #=> "$+<=>^`|~"
|
|
149
139
|
|
150
140
|
# Ranged Selections
|
151
141
|
# v<hex>w<hex>_<filter>
|
152
|
-
DIGITS[:v1d7d8w1d7e1_Any]
|
142
|
+
DIGITS[:v1d7d8w1d7e1_Any] #=> "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡"
|
153
143
|
# i<dec>j<dec>_<filter>
|
154
144
|
DIGITS[:i120488j120513_Any] #=> "𝚨𝚩𝚪𝚫𝚬𝚭𝚮𝚯𝚰𝚱𝚲𝚳𝚴𝚵𝚶𝚷𝚸𝚹𝚺𝚻𝚼𝚽𝚾𝚿𝛀𝛁"
|
155
145
|
|
@@ -160,19 +150,19 @@ DIGITS[:u61u62] #=> "ab"
|
|
160
150
|
DIGITS[:k97k98] #=> "ab"
|
161
151
|
|
162
152
|
# BaseConvert's Custom Sets
|
163
|
-
DIGITS[:bangs]
|
164
|
-
DIGITS[:typers]
|
165
|
-
DIGITS[:operators]
|
153
|
+
DIGITS[:bangs] #=> "!?"
|
154
|
+
DIGITS[:typers] #=> "$&@"
|
155
|
+
DIGITS[:operators] #=> "*+-/<=>^~"
|
166
156
|
DIGITS[:separators] #=> ",.:;|"
|
167
|
-
DIGITS[:scapes]
|
168
|
-
DIGITS[:groupers]
|
169
|
-
DIGITS[:quotes]
|
170
|
-
DIGITS[:quoters]
|
171
|
-
DIGITS[:spacers]
|
172
|
-
DIGITS[:ambiguous]
|
157
|
+
DIGITS[:scapes] #=> "#\\"
|
158
|
+
DIGITS[:groupers] #=> "()[]{}"
|
159
|
+
DIGITS[:quotes] #=> "\"'`"
|
160
|
+
DIGITS[:quoters] #=> "%\"'`"
|
161
|
+
DIGITS[:spacers] #=> "_ "
|
162
|
+
DIGITS[:ambiguous] #=> "012568BDGIOQSZl"
|
173
163
|
|
174
164
|
# Composition, add merge:
|
175
|
-
DIGITS[:d_ambiguous]
|
165
|
+
DIGITS[:d_ambiguous] #=> "0123456789BDGIOQSZl"
|
176
166
|
# Composition, add top:
|
177
167
|
DIGITS[:'d+ambiguous'] #=> "3479012568BDGIOQSZl"
|
178
168
|
# Composition, subtract:
|
@@ -183,11 +173,12 @@ DIGITS[:'d-ambiguous'] #=> "3479"
|
|
183
173
|
DIGITS[:alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers]
|
184
174
|
#=> "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%\"'`_ "
|
185
175
|
# :B64 is:
|
186
|
-
DIGITS[:LN_k43k47]
|
176
|
+
DIGITS[:LN_k43k47]
|
177
|
+
#=> "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
187
178
|
# :U47 is:
|
188
|
-
DIGITS[:'alnum-ambiguous']
|
179
|
+
DIGITS[:'alnum-ambiguous']
|
180
|
+
#=> "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"
|
189
181
|
```
|
190
|
-
|
191
182
|
### class FromTo
|
192
183
|
|
193
184
|
* `new(base: 10 Integer|Symbol|String, to_base: base, digits: :P95 String|Symbol|Integer, to_digits: digits) #=> FromTo`
|
@@ -195,16 +186,14 @@ DIGITS[:'alnum-ambiguous'] #=> "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"
|
|
195
186
|
* `#convert(counter String|Integer) #=> String`
|
196
187
|
|
197
188
|
Example:
|
198
|
-
|
199
189
|
```ruby
|
200
190
|
h2b = BaseConvert::FromTo.new(base: 16, digits: :P95, to_base: 64, to_digits: :B64)
|
201
|
-
h2b
|
191
|
+
h2b #=> 16:P95,64:B64
|
202
192
|
h2b['FFF'] #=> "//"
|
203
193
|
b2h = BaseConvert::FromTo.new(base: 64, digits: :B64, to_base: 16, to_digits: :P95)
|
204
|
-
b2h
|
205
|
-
b2h['//']
|
194
|
+
b2h #=> 64:B64,16:P95
|
195
|
+
b2h['//'] #=> "FFF"
|
206
196
|
```
|
207
|
-
|
208
197
|
### class Number
|
209
198
|
|
210
199
|
* `new(counter= 0 Integer|String, base: nil Integer|Symbol|String, digits: nil String|Symbol|Integer, validate: true TrueClass|FalseClass) #=> Number`
|
@@ -217,24 +206,22 @@ b2h['//'] #=> "FFF"
|
|
217
206
|
* `#to_digits(digits String|Symbol|Integer, base=@base Integer|Symbol|String, validate=@validate TrueClass|FalseClass) #=> Number`
|
218
207
|
|
219
208
|
Example:
|
220
|
-
|
221
209
|
```ruby
|
222
210
|
a = BaseConvert::Number.new('FFF', base: 16, digits: :P95)
|
223
|
-
a
|
211
|
+
a #=> FFF 16:P95
|
224
212
|
a.to_i #=> 4095
|
225
213
|
b = a.to_digits(:U47)
|
226
|
-
b
|
214
|
+
b #=> RRR 16:U47
|
227
215
|
b.to_i #=> 4095
|
228
216
|
c = b.to_base(64, :B64)
|
229
|
-
c
|
217
|
+
c #=> // 64:B64
|
230
218
|
c.to_i #=> 4095
|
231
219
|
```
|
232
|
-
|
233
220
|
## LICENSE:
|
234
221
|
|
235
222
|
(The MIT License)
|
236
223
|
|
237
|
-
Copyright (c)
|
224
|
+
Copyright (c) 2022 CarlosJHR64
|
238
225
|
|
239
226
|
Permission is hereby granted, free of charge, to any person obtaining
|
240
227
|
a copy of this software and associated documentation files (the
|
data/lib/base_convert/base.rb
CHANGED
@@ -1,24 +1,65 @@
|
|
1
1
|
module BaseConvert
|
2
|
-
class Base < Hash
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
18
19
|
end
|
20
|
+
raise 'base must be greater than 1' unless base > 1
|
21
|
+
base
|
19
22
|
end
|
20
|
-
raise 'base must be greater than 1' unless base > 1
|
21
|
-
base
|
22
23
|
end
|
23
|
-
|
24
|
+
BASE = Base[
|
25
|
+
# 95
|
26
|
+
P95: 95,
|
27
|
+
print: 95,
|
28
|
+
# 94
|
29
|
+
G94: 94, g: 94, graph: 94,
|
30
|
+
# 91
|
31
|
+
Q91: 91, qgraph: 91, q: 91,
|
32
|
+
# 64
|
33
|
+
B64: 64, base64: 64, b64: 64,
|
34
|
+
# 63
|
35
|
+
W63: 63, word: 63, w: 63,
|
36
|
+
# 52
|
37
|
+
letters: 52, l: 52, L: 52,
|
38
|
+
# 47
|
39
|
+
U47: 47, unambiguous: 47, u: 47,
|
40
|
+
# 16
|
41
|
+
hexadecimal: 16, hex: 16, h: 16,
|
42
|
+
# 15
|
43
|
+
ambiguous: 15,
|
44
|
+
# 10
|
45
|
+
decimal: 10, dec: 10, d: 10,
|
46
|
+
# 9
|
47
|
+
operators: 9,
|
48
|
+
# 8
|
49
|
+
octal: 8, oct: 8, o: 8,
|
50
|
+
# 6
|
51
|
+
groupers: 6,
|
52
|
+
# 5
|
53
|
+
separators: 5,
|
54
|
+
# 4
|
55
|
+
quoters: 4,
|
56
|
+
# 3
|
57
|
+
typers: 3,
|
58
|
+
quotes: 3,
|
59
|
+
# 2
|
60
|
+
binary: 2, bin: 2, b: 2,
|
61
|
+
bangs: 2,
|
62
|
+
scapes: 2,
|
63
|
+
spacers: 2,
|
64
|
+
]
|
24
65
|
end
|
data/lib/base_convert/chars.rb
CHANGED
@@ -1,33 +1,38 @@
|
|
1
1
|
module BaseConvert
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
# Chars provides ways of populating an ordered(as constructed) set
|
3
|
+
# with characters in UTF-8.
|
4
|
+
class Chars
|
5
|
+
def initialize
|
6
|
+
@start,@stop,@a = 32,126,[]
|
6
7
|
end
|
7
8
|
|
9
|
+
attr_accessor :start,:stop
|
10
|
+
def to_a = @a
|
11
|
+
def to_s = @a.join
|
12
|
+
|
13
|
+
# Chars can search a range in UTF-8 for character classes.
|
14
|
+
# Use Chars#set to set the start and stop of the range.
|
8
15
|
# i<n>: @start=n.to_i
|
9
16
|
# v<n>: @start=n.to_i(16)
|
10
17
|
# j<n>: @stop=n.to_i
|
11
18
|
# w<n>: @stop=n.to_i(16)
|
12
19
|
def set(s)
|
20
|
+
unless /^([ij]\d+)|([vw]\h+)$/.match?(s)
|
21
|
+
raise 'expected /^([ij]\d+)|([vw]\h+)$/'
|
22
|
+
end
|
13
23
|
t,n = s[0],s[1..-1]
|
14
24
|
case t
|
15
25
|
when 'i','v'
|
16
26
|
@start = n.to_i((t=='v')? 16 : 10)
|
17
27
|
when 'j','w'
|
18
28
|
@stop = n.to_i((t=='w')? 16 : 10)
|
19
|
-
else
|
20
|
-
raise 'expected /^([ij]\d+)|([vw]\h+)$/'
|
21
29
|
end
|
22
30
|
end
|
23
31
|
|
24
32
|
def chars_in(x)
|
25
33
|
case x
|
26
34
|
when Regexp
|
27
|
-
@start
|
28
|
-
c = l.chr(Encoding::UTF_8)
|
29
|
-
yield c if x.match? c
|
30
|
-
end
|
35
|
+
(@start..@stop).each{x.match?(c=_1.chr(Encoding::UTF_8)) && yield(c)}
|
31
36
|
when Symbol
|
32
37
|
yield x[1..-1].to_i((x[0]=='u')? 16: 10).chr(Encoding::UTF_8)
|
33
38
|
when String
|
@@ -39,21 +44,8 @@ module BaseConvert
|
|
39
44
|
end
|
40
45
|
end
|
41
46
|
|
42
|
-
def add(x)
|
43
|
-
|
44
|
-
|
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
|
47
|
+
def add(x) = chars_in(x){@a.push _1 unless @a.include?_1}
|
48
|
+
def top(x) = chars_in(x){@a.delete _1;@a.push _1}
|
49
|
+
def remove(x) = chars_in(x){@a.delete _1}
|
58
50
|
end
|
59
51
|
end
|
data/lib/base_convert/digits.rb
CHANGED
@@ -1,96 +1,134 @@
|
|
1
1
|
module BaseConvert
|
2
|
-
class Digits < Hash
|
3
|
-
|
4
|
-
|
5
|
-
if self.has_key?(key)
|
6
|
-
d = super(key)
|
7
|
-
return d.is_a?(Symbol)? self[d]: d
|
2
|
+
class Digits < Hash
|
3
|
+
def initialize
|
4
|
+
@registry = [:P95, :B64, :U47, :G94, :Q91, :W63]
|
8
5
|
end
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
when
|
32
|
-
chars.
|
33
|
-
when
|
34
|
-
chars.remove
|
6
|
+
|
7
|
+
# Set super's [] definition as get
|
8
|
+
alias :get :[]
|
9
|
+
def [](key)
|
10
|
+
return (_=get key).is_a?(Symbol)?self[_]:_ if self.has_key? key
|
11
|
+
case key
|
12
|
+
when Symbol
|
13
|
+
chars = Chars.new
|
14
|
+
key.to_s.scan(/[+-]?[[:alnum:]]+/).each do |type|
|
15
|
+
if self.has_key?(_=type.to_sym)
|
16
|
+
chars.add super(_)
|
17
|
+
next
|
18
|
+
end
|
19
|
+
case type
|
20
|
+
when /^((u\h+)|(k\d+))+$/ # add single char by code
|
21
|
+
type.scan(/[uk]\h+/).each{chars.top _1.to_sym}
|
22
|
+
when /^(([ij]\d+)|([vw]\h+))+$/ # set start/stop range
|
23
|
+
type.scan(/[ijvw]\h+/).each{chars.set _1}
|
24
|
+
when /^[a-z][a-z]+$/ # add by POSIX bracket expression
|
25
|
+
chars.add Regexp.new "[[:#{type}:]]"
|
26
|
+
when /^[a-z]$/ # add by metacharacter
|
27
|
+
chars.add Regexp.new "\\#{type}"
|
28
|
+
when /^[A-Z]+$/i # add by property
|
29
|
+
type.scan(/[A-Z][a-z]*/).each{chars.add(/\p{#{_1}}/)}
|
30
|
+
when /^([+-])(\w+)$/ # top or remove chars of key given
|
31
|
+
(_=self[$2.to_sym]) and ($1=='+')? chars.top(_): chars.remove(_)
|
32
|
+
when /^(\p{L}+)(\d+)$/ # a registered set
|
33
|
+
l,m = $1,$2.to_i-1
|
34
|
+
n = self.keys.select{_1=~/^#{l}\d+$/}
|
35
|
+
.map{_1.to_s.sub(l,'').to_i}.max
|
36
|
+
raise "no #{l}<n> digits defined" if n.nil?
|
37
|
+
raise "out of range of #{l}#{n}" unless m<n
|
38
|
+
chars.add self[:"#{l}#{n}"][0..m]
|
39
|
+
else
|
40
|
+
raise "unrecognized digits key: #{type}"
|
35
41
|
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
42
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
digits = nil # set as a side effect...
|
49
|
-
unless registry.detect{|_|(digits=self[_]).start_with? key}
|
50
|
-
# ...here -------------->^^^^^
|
43
|
+
return chars.to_s.freeze
|
44
|
+
when String
|
45
|
+
_=@registry.lazy.map{self[_1]}.detect{_1.start_with? key} and return _
|
51
46
|
raise 'need at least 2 digits' unless key.length > 1
|
52
|
-
|
47
|
+
if key.length > key.chars.uniq.length
|
48
|
+
raise 'digits must not have duplicates'
|
49
|
+
end
|
53
50
|
return key
|
51
|
+
when Integer
|
52
|
+
raise 'need digits to cover base' if key > 95
|
53
|
+
return self[:P95] # Defined in configuration.rb
|
54
54
|
end
|
55
|
-
|
56
|
-
when Integer
|
57
|
-
raise 'need digits to cover base' if key > 95
|
58
|
-
return self[:P95] # Defined in configuration.rb
|
55
|
+
raise 'digits must be String|Symbol|Integer'
|
59
56
|
end
|
60
|
-
raise 'digits must be String|Symbol|Integer'
|
61
|
-
end
|
62
57
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
58
|
+
def registry(d=nil)
|
59
|
+
# BaseConvert::Number memoizes and uses specifically :P95, :B64, and :U47;
|
60
|
+
# giving these precedence above the rest.
|
61
|
+
d ? @registry.detect{|_|self[_].start_with? d}: @registry
|
62
|
+
end
|
69
63
|
|
70
|
-
|
71
|
-
|
72
|
-
|
64
|
+
def label(d)
|
65
|
+
registry(d) or (d[0..1]+d[-2..-1]).to_sym
|
66
|
+
end
|
73
67
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
68
|
+
def memoize!(keys=@registry)
|
69
|
+
[*keys].each do |k|
|
70
|
+
# follow Symbol links 'till nil|String
|
71
|
+
while s=get(k) and not s.is_a? String
|
72
|
+
raise 'expected Symbol' unless s.is_a? Symbol
|
73
|
+
k = s
|
74
|
+
end
|
75
|
+
self[k]=self[k] unless s # memoize if needed
|
80
76
|
end
|
81
|
-
self[k]=self[k] if s.nil? # if not memoized, memoize!
|
82
77
|
end
|
83
|
-
end
|
84
78
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
79
|
+
def forget!(keys=@registry)
|
80
|
+
[*keys].each do |k|
|
81
|
+
# follow Symbol links 'till nil|String
|
82
|
+
while s = get(k) and not s.is_a? String
|
83
|
+
raise 'expected Symbol' unless s.is_a? Symbol
|
84
|
+
k = s
|
85
|
+
end
|
86
|
+
self.delete(k) if s
|
91
87
|
end
|
92
|
-
self.delete(k) if s.is_a? String
|
93
88
|
end
|
94
89
|
end
|
95
|
-
|
90
|
+
|
91
|
+
DIGITS = Digits.new
|
92
|
+
|
93
|
+
# Naming these letter sequences is inpired by
|
94
|
+
# (but not the same as)
|
95
|
+
# Unicode character’s General Category.
|
96
|
+
DIGITS[:bangs] = '!?'.freeze # Used as method name suffix
|
97
|
+
DIGITS[:typers] = '$&@'.freeze # Used as variable name prefix
|
98
|
+
DIGITS[:operators] = '*+-/<=>^~'.freeze # Used as mathematical operators
|
99
|
+
DIGITS[:separators] = ',.:;|'.freeze # Used to separated items
|
100
|
+
DIGITS[:scapes] = '#\\'.freeze # Used to escape what's next
|
101
|
+
DIGITS[:groupers] = '()[]{}'.freeze # Used to group items
|
102
|
+
DIGITS[:quotes] = %("'`).freeze # Quotes
|
103
|
+
DIGITS[:quoters] = %(\%"'`).freeze # Used to quote strings('%' not ASCII ordered)
|
104
|
+
DIGITS[:spacers] = '_ '.freeze # 1_000 == 1000 #=> true (Not ASCII ordered)
|
105
|
+
DIGITS[:ambiguous] = '012568BDGIOQSZl'.freeze # ASCII ordered ambiguous characters
|
106
|
+
|
107
|
+
### Recursive string constructors ###
|
108
|
+
# 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?$&@*+-/<=>^~,.:;|#\\()[]{}%"'`_
|
109
|
+
DIGITS[:P95] = :alnum_bangs_typers_operators_separators_scapes_groupers_quoters_spacers
|
110
|
+
# 0123456789ABCDEF
|
111
|
+
DIGITS[:hexadecimal] = DIGITS[:hex] = DIGITS[:h] = :P16
|
112
|
+
# 0123456789
|
113
|
+
DIGITS[:decimal] = DIGITS[:dec] = :P10
|
114
|
+
# 01234567
|
115
|
+
DIGITS[:octal] = DIGITS[:oct] = DIGITS[:o] = :P8
|
116
|
+
# 01
|
117
|
+
DIGITS[:b] = DIGITS[:bin] = DIGITS[:binary] = :P2
|
118
|
+
|
119
|
+
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
120
|
+
DIGITS[:G94] = DIGITS[:g] = :graph
|
121
|
+
|
122
|
+
# !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~
|
123
|
+
DIGITS[:Q91] = DIGITS[:qgraph] = DIGITS[:q] = :'graph-quotes'
|
124
|
+
|
125
|
+
# ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
|
126
|
+
DIGITS[:base64] = DIGITS[:b64] = DIGITS[:B64] = :LN_k43k47
|
127
|
+
DIGITS[:letters] = DIGITS[:l] = :B52 # subset of B64
|
128
|
+
|
129
|
+
# 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz
|
130
|
+
DIGITS[:word] = DIGITS[:W63] = :w
|
131
|
+
|
132
|
+
# 3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz
|
133
|
+
DIGITS[:unambiguous] = DIGITS[:U47] = DIGITS[:u] = :'alnum-ambiguous'
|
96
134
|
end
|
data/lib/base_convert/from_to.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
# http://rosettacode.org/wiki/Non-decimal_radices/Convert#Ruby
|
2
2
|
module BaseConvert
|
3
|
+
module Methods
|
3
4
|
def toi(string=to_s, base=@base, digits=@digits)
|
4
5
|
return nil if string.empty?
|
5
|
-
|
6
|
-
string.each_char do |c|
|
7
|
-
index = digits.index(c)
|
8
|
-
integer = integer * base + index
|
9
|
-
end
|
10
|
-
integer
|
6
|
+
string.chars.inject(0){_1*base + digits.index(_2)}
|
11
7
|
end
|
12
8
|
|
13
9
|
def tos(integer=to_i, base=@base, digits=@digits)
|
@@ -21,9 +17,10 @@ module BaseConvert
|
|
21
17
|
string
|
22
18
|
end
|
23
19
|
|
24
|
-
def
|
25
|
-
|
20
|
+
def chars_ordered?(digits=@digits)
|
21
|
+
digits.chars.each_cons(2).all?{_1<_2}
|
26
22
|
end
|
27
23
|
|
28
24
|
extend self
|
29
25
|
end
|
26
|
+
end
|
data/lib/base_convert/number.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
module BaseConvert
|
2
2
|
class Number
|
3
|
-
include
|
3
|
+
include Methods
|
4
4
|
DIGITS.memoize!
|
5
|
+
INDEXa = DIGITS[:P95].index('a')
|
5
6
|
|
6
|
-
def self.infer(string)
|
7
|
+
def self.infer(string, error:'digits not all in P95')
|
7
8
|
p95 = DIGITS[:P95]
|
8
9
|
return 2, p95 if string.empty?
|
9
10
|
chars = string.chars
|
10
|
-
raise
|
11
|
+
raise error unless chars.all?{|_|p95.include?_}
|
11
12
|
max = chars.map{|_|p95.index(_)}.max
|
12
13
|
return 95, p95 if max == 94 # string has a space digit.
|
13
14
|
return 2, p95 if max < 2
|
@@ -26,20 +27,16 @@ class Number
|
|
26
27
|
|
27
28
|
attr_reader :base, :digits
|
28
29
|
def initialize(counter=0, base: nil, digits: nil, validate: true)
|
29
|
-
#
|
30
|
-
case validate
|
31
|
-
when true, false
|
32
|
-
@validate = validate
|
33
|
-
else
|
34
|
-
raise 'validate must be either true or false'
|
35
|
-
end
|
30
|
+
@validate = !!validate # ensure boolean
|
36
31
|
|
37
32
|
# counter
|
38
33
|
string = nil
|
39
34
|
case counter
|
40
35
|
when String
|
41
36
|
string = counter
|
42
|
-
|
37
|
+
if base.nil? and digits.nil?
|
38
|
+
base, digits = Number.infer(counter, error:'need digits to cover string')
|
39
|
+
end
|
43
40
|
when Integer
|
44
41
|
@integer = counter
|
45
42
|
base, digits = 10, DIGITS[:P95] if base.nil? and digits.nil?
|
@@ -51,21 +48,22 @@ class Number
|
|
51
48
|
@digits = DIGITS[digits || base]
|
52
49
|
|
53
50
|
# base
|
54
|
-
base = digits
|
51
|
+
base = digits if base.nil? and digits.is_a? Symbol
|
55
52
|
@base = BASE[base || @digits.length]
|
56
53
|
|
57
54
|
# validate
|
58
55
|
if @validate
|
59
56
|
raise 'digits must cover base' if @base > @digits.length
|
60
57
|
unless string.nil? or string.empty?
|
61
|
-
indeces = string.chars.map{
|
62
|
-
if missing = indeces.any?{
|
58
|
+
indeces = string.chars.map{@digits.index _1}
|
59
|
+
if missing = indeces.any?{_1.nil?} or exceeding = indeces.any?{_1>=@base}
|
63
60
|
if @base <= INDEXa and DIGITS[:P95].start_with?(@digits)
|
61
|
+
# User ignored case, so fix it...
|
64
62
|
string = string.upcase
|
65
|
-
indeces = string.chars.map{
|
66
|
-
missing = indeces.any?{
|
63
|
+
indeces = string.chars.map{@digits.index _1}
|
64
|
+
missing = indeces.any?{_1.nil?} or exceeding = indeces.any?{_1>=@base}
|
67
65
|
end
|
68
|
-
raise 'digits must cover string'
|
66
|
+
raise 'digits must cover string' if missing
|
69
67
|
raise 'digits in string must be under base' if exceeding
|
70
68
|
end
|
71
69
|
end
|
@@ -82,15 +80,9 @@ class Number
|
|
82
80
|
"#{to_s} #{@base}:#{d}"
|
83
81
|
end
|
84
82
|
|
85
|
-
def validate?
|
86
|
-
@validate
|
87
|
-
end
|
88
|
-
|
83
|
+
def validate? = @validate
|
89
84
|
alias to_s tos
|
90
|
-
|
91
|
-
def to_i
|
92
|
-
@integer
|
93
|
-
end
|
85
|
+
def to_i = @integer
|
94
86
|
|
95
87
|
def to_base(base, digits=(base.is_a?Symbol)? DIGITS[base] : @digits, validate=@validate)
|
96
88
|
Number.new @integer, base: base, digits: digits, validate: validate
|
data/lib/base_convert.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
module BaseConvert
|
2
|
-
VERSION = '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
require 'base_convert/number'
|
2
|
+
VERSION = '7.0.221226'
|
3
|
+
autoload :Methods, 'base_convert/methods.rb'
|
4
|
+
autoload :Chars, 'base_convert/chars.rb'
|
5
|
+
autoload :DIGITS, 'base_convert/digits.rb'
|
6
|
+
autoload :BASE, 'base_convert/base.rb'
|
7
|
+
autoload :FromTo, 'base_convert/from_to.rb'
|
8
|
+
autoload :Number, 'base_convert/number.rb'
|
10
9
|
end
|
11
10
|
#`ruby`
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: base_convert
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 7.0.221226
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
autorequire:
|
7
|
+
- CarlosJHR64
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
BaseConvert - Number base conversion.
|
@@ -25,17 +25,16 @@ files:
|
|
25
25
|
- README.md
|
26
26
|
- lib/base_convert.rb
|
27
27
|
- lib/base_convert/base.rb
|
28
|
-
- lib/base_convert/base_convert.rb
|
29
28
|
- lib/base_convert/chars.rb
|
30
|
-
- lib/base_convert/configuration.rb
|
31
29
|
- lib/base_convert/digits.rb
|
32
30
|
- lib/base_convert/from_to.rb
|
31
|
+
- lib/base_convert/methods.rb
|
33
32
|
- lib/base_convert/number.rb
|
34
33
|
homepage: https://github.com/carlosjhr64/base_convert
|
35
34
|
licenses:
|
36
35
|
- MIT
|
37
36
|
metadata: {}
|
38
|
-
post_install_message:
|
37
|
+
post_install_message:
|
39
38
|
rdoc_options: []
|
40
39
|
require_paths:
|
41
40
|
- lib
|
@@ -50,9 +49,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
49
|
- !ruby/object:Gem::Version
|
51
50
|
version: '0'
|
52
51
|
requirements:
|
53
|
-
- 'ruby: ruby 3.
|
54
|
-
rubygems_version: 3.
|
55
|
-
signing_key:
|
52
|
+
- 'ruby: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [aarch64-linux]'
|
53
|
+
rubygems_version: 3.3.7
|
54
|
+
signing_key:
|
56
55
|
specification_version: 4
|
57
56
|
summary: BaseConvert - Number base conversion.
|
58
57
|
test_files: []
|
@@ -1,88 +0,0 @@
|
|
1
|
-
module BaseConvert
|
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
|
-
]
|
88
|
-
end
|