string_pattern 2.1.4 → 2.2.3
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 +2 -0
- data/lib/string/pattern/add_to_ruby.rb +74 -65
- data/lib/string/pattern/analyze.rb +195 -0
- data/lib/string/pattern/generate.rb +579 -0
- data/lib/string/pattern/validate.rb +220 -0
- data/lib/string_pattern.rb +14 -987
- metadata +12 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c451e4295f5c62ea8b7c8113815a0c7a2b5c70a739826fdf651a7fb99a75be48
|
4
|
+
data.tar.gz: 2445e4958a2bf96b70e0ce99f4df31ab02a61183a496289a1b20b3360e2fecaf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 650a16f6a2cda5c762f2f685b4fe515848135a6c4995ba08504ec80435696d4e1ab6289adaf4aae839ca0d77978338d2603411a7330fe2db0f2bede587554cfd
|
7
|
+
data.tar.gz: 996deb9300188c286dc0a051f744262367f928192e5c30fcd981f7f964283463f2dc606c4876163378397b767ed235f51bc749bac55e801866810aa19318da91
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# StringPattern
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/string_pattern)
|
4
|
+
[](https://github.com/MarioRuiz/string_pattern)
|
5
|
+
[](https://coveralls.io/github/MarioRuiz/string_pattern?branch=master)
|
4
6
|
|
5
7
|
With this gem, you can easily generate strings supplying a very simple pattern. Even generate random words in English or Spanish.
|
6
8
|
Also, you can validate if a text fulfills a specific pattern or even generate a string following a pattern and returning the wrong length, value... for testing your applications. Perfect to be used in test data factories.
|
@@ -35,10 +35,21 @@ class String
|
|
35
35
|
# Convert to CamelCase a string
|
36
36
|
########################################################
|
37
37
|
def to_camel_case
|
38
|
-
return self if self !~ /_/ && self !~ /\s/ && self =~
|
38
|
+
return self if self !~ /_/ && self !~ /\s/ && self =~ /^[A-Z]+.*/
|
39
39
|
|
40
|
+
gsub(/[^a-zA-Z0-9ññÑáéíóúÁÉÍÓÚüÜ_]/, "_")
|
41
|
+
.split("_").map(&:capitalize).join
|
42
|
+
end
|
43
|
+
|
44
|
+
########################################################
|
45
|
+
# Convert to snake_case a string
|
46
|
+
########################################################
|
47
|
+
def to_snake_case
|
40
48
|
gsub(/\W/, '_')
|
41
|
-
.
|
49
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
50
|
+
.gsub(/([a-z])([A-Z])/, '\1_\2')
|
51
|
+
.downcase
|
52
|
+
.gsub(/_+/, '_')
|
42
53
|
end
|
43
54
|
end
|
44
55
|
|
@@ -70,40 +81,39 @@ class Regexp
|
|
70
81
|
# adds method to convert a Regexp to StringPattern
|
71
82
|
# returns an array of string patterns or just one string pattern
|
72
83
|
def to_sp
|
73
|
-
regexp_s = self.to_s
|
84
|
+
regexp_s = self.to_s
|
74
85
|
return StringPattern.cache[regexp_s] unless StringPattern.cache[regexp_s].nil?
|
75
86
|
regexp = Regexp.new regexp_s
|
76
|
-
require
|
87
|
+
require "regexp_parser"
|
77
88
|
default_infinite = StringPattern.default_infinite
|
78
89
|
pata = []
|
79
|
-
pats =
|
90
|
+
pats = ""
|
80
91
|
patg = [] # for (aa|bb|cc) group
|
81
92
|
set = false
|
82
93
|
capture = false
|
83
94
|
|
84
|
-
range =
|
85
|
-
fixed_text=false
|
86
|
-
last_char = (regexp.to_s.gsub("?-mix:",
|
95
|
+
range = ""
|
96
|
+
fixed_text = false
|
97
|
+
last_char = (regexp.to_s.gsub("?-mix:", "").length) - 2
|
87
98
|
Regexp::Scanner.scan regexp do |type, token, text, ts, te|
|
88
99
|
if type == :escape
|
89
100
|
if token == :dot
|
90
101
|
token = :literal
|
91
|
-
text =
|
102
|
+
text = "."
|
92
103
|
elsif token == :literal and text.size == 2
|
93
104
|
text = text[1]
|
94
|
-
else
|
105
|
+
else
|
95
106
|
puts "Report token not controlled: type: #{type}, token: #{token}, text: '#{text}' [#{ts}..#{te}]"
|
96
107
|
end
|
97
108
|
end
|
98
109
|
|
99
|
-
|
100
110
|
unless set || (token == :interval) || (token == :zero_or_one) ||
|
101
|
-
(token == :zero_or_more) || (token == :one_or_more) || (pats ==
|
102
|
-
if (pats[0] ==
|
103
|
-
pats[0] =
|
111
|
+
(token == :zero_or_more) || (token == :one_or_more) || (pats == "")
|
112
|
+
if (pats[0] == "[") && (pats[-1] == "]")
|
113
|
+
pats[0] = ""
|
104
114
|
if (token == :alternation) || !patg.empty?
|
105
|
-
if fixed_text
|
106
|
-
if patg.size==0
|
115
|
+
if fixed_text
|
116
|
+
if patg.size == 0
|
107
117
|
patg << (pata.pop + pats.chop)
|
108
118
|
else
|
109
119
|
patg[-1] += pats.chop
|
@@ -112,15 +122,15 @@ class Regexp
|
|
112
122
|
patg << pats.chop
|
113
123
|
end
|
114
124
|
else
|
115
|
-
if fixed_text
|
116
|
-
pata[-1]+=pats.chop
|
125
|
+
if fixed_text
|
126
|
+
pata[-1] += pats.chop
|
117
127
|
else
|
118
|
-
if pats.size==2
|
128
|
+
if pats.size == 2
|
119
129
|
pata << pats.chop #jal
|
120
130
|
else
|
121
131
|
pata << "1:[#{pats}" #jal
|
122
132
|
end
|
123
|
-
if last_char==te and type
|
133
|
+
if last_char == te and type == :literal and token == :literal
|
124
134
|
pata << text
|
125
135
|
pats = ""
|
126
136
|
next
|
@@ -134,66 +144,66 @@ class Regexp
|
|
134
144
|
pata << "1:#{pats}"
|
135
145
|
end
|
136
146
|
end
|
137
|
-
pats =
|
147
|
+
pats = ""
|
138
148
|
end
|
139
|
-
fixed_text=false
|
149
|
+
fixed_text = false
|
140
150
|
|
141
151
|
case token
|
142
152
|
when :open
|
143
153
|
set = true
|
144
|
-
pats +=
|
154
|
+
pats += "["
|
145
155
|
when :close
|
146
156
|
if type == :set
|
147
157
|
set = false
|
148
|
-
if pats[-1] ==
|
158
|
+
if pats[-1] == "["
|
149
159
|
pats.chop!
|
150
160
|
else
|
151
|
-
pats +=
|
161
|
+
pats += "]"
|
152
162
|
end
|
153
163
|
elsif type == :group
|
154
164
|
capture = false
|
155
165
|
unless patg.empty?
|
156
|
-
patg << pats if pats.to_s !=
|
166
|
+
patg << pats if pats.to_s != ""
|
157
167
|
pata << patg
|
158
168
|
patg = []
|
159
|
-
pats =
|
169
|
+
pats = ""
|
160
170
|
end
|
161
171
|
end
|
162
172
|
when :capture
|
163
173
|
capture = true if type == :group
|
164
174
|
when :alternation
|
165
175
|
if type == :meta
|
166
|
-
if pats !=
|
176
|
+
if pats != ""
|
167
177
|
patg << pats
|
168
|
-
pats =
|
178
|
+
pats = ""
|
169
179
|
elsif patg.empty?
|
170
180
|
# for the case the first element was not added to patg and was on pata fex: (a+|b|c)
|
171
181
|
patg << pata.pop
|
172
|
-
|
182
|
+
end
|
173
183
|
end
|
174
184
|
when :range
|
175
185
|
range = pats[-1]
|
176
186
|
pats.chop!
|
177
187
|
when :digit
|
178
|
-
pats +=
|
188
|
+
pats += "n"
|
179
189
|
when :nondigit
|
180
|
-
pats +=
|
190
|
+
pats += "*[%0123456789%]"
|
181
191
|
when :space
|
182
|
-
pats +=
|
192
|
+
pats += "_"
|
183
193
|
when :nonspace
|
184
|
-
pats +=
|
194
|
+
pats += "*[% %]"
|
185
195
|
when :word
|
186
|
-
pats +=
|
196
|
+
pats += "Ln_"
|
187
197
|
when :nonword
|
188
|
-
pats +=
|
198
|
+
pats += "$"
|
189
199
|
when :word_boundary
|
190
|
-
pats +=
|
200
|
+
pats += "$"
|
191
201
|
when :dot
|
192
|
-
pats +=
|
202
|
+
pats += "*"
|
193
203
|
when :literal
|
194
|
-
if range ==
|
204
|
+
if range == ""
|
195
205
|
if text.size > 1
|
196
|
-
fixed_text=true
|
206
|
+
fixed_text = true
|
197
207
|
if !patg.empty?
|
198
208
|
patg << text.chop
|
199
209
|
else
|
@@ -204,42 +214,41 @@ class Regexp
|
|
204
214
|
pats += text
|
205
215
|
end
|
206
216
|
else
|
207
|
-
range = range +
|
208
|
-
if range ==
|
209
|
-
pats =
|
210
|
-
elsif range ==
|
211
|
-
pats =
|
212
|
-
elsif range ==
|
213
|
-
pats =
|
217
|
+
range = range + "-" + text
|
218
|
+
if range == "a-z"
|
219
|
+
pats = "x" + pats
|
220
|
+
elsif range == "A-Z"
|
221
|
+
pats = "X" + pats
|
222
|
+
elsif range == "0-9"
|
223
|
+
pats = "n" + pats
|
214
224
|
else
|
215
225
|
pats += if set
|
216
226
|
(range[0]..range[2]).to_a.join
|
217
227
|
else
|
218
|
-
|
219
|
-
|
220
|
-
|
228
|
+
"[" + (range[0]..range[2]).to_a.join + "]"
|
229
|
+
end
|
221
230
|
end
|
222
|
-
range =
|
231
|
+
range = ""
|
223
232
|
end
|
224
|
-
pats =
|
233
|
+
pats = "[" + pats + "]" unless set
|
225
234
|
when :interval
|
226
|
-
size = text.sub(
|
227
|
-
size.chop! if size[-1] ==
|
228
|
-
pats = size +
|
235
|
+
size = text.sub(",", "-").sub("{", "").sub("}", "")
|
236
|
+
size.chop! if size[-1] == "-"
|
237
|
+
pats = size + ":" + pats
|
229
238
|
if !patg.empty?
|
230
239
|
patg << pats
|
231
240
|
else
|
232
241
|
pata << pats
|
233
242
|
end
|
234
|
-
pats =
|
243
|
+
pats = ""
|
235
244
|
when :zero_or_one
|
236
|
-
pats =
|
245
|
+
pats = "0-1:" + pats
|
237
246
|
if !patg.empty?
|
238
247
|
patg << pats
|
239
248
|
else
|
240
249
|
pata << pats
|
241
250
|
end
|
242
|
-
pats =
|
251
|
+
pats = ""
|
243
252
|
when :zero_or_more
|
244
253
|
pats = "0-#{default_infinite}:" + pats
|
245
254
|
if !patg.empty?
|
@@ -247,7 +256,7 @@ class Regexp
|
|
247
256
|
else
|
248
257
|
pata << pats
|
249
258
|
end
|
250
|
-
pats =
|
259
|
+
pats = ""
|
251
260
|
when :one_or_more
|
252
261
|
pats = "1-#{default_infinite}:" + pats
|
253
262
|
if !patg.empty?
|
@@ -255,19 +264,19 @@ class Regexp
|
|
255
264
|
else
|
256
265
|
pata << pats
|
257
266
|
end
|
258
|
-
pats =
|
267
|
+
pats = ""
|
259
268
|
end
|
260
269
|
end
|
261
|
-
if pats!=""
|
262
|
-
if pata.empty?
|
263
|
-
if pats[0]=="[" and pats[-1]=="]" #fex: /[12ab]/
|
270
|
+
if pats != ""
|
271
|
+
if pata.empty?
|
272
|
+
if pats[0] == "[" and pats[-1] == "]" #fex: /[12ab]/
|
264
273
|
pata = ["1:#{pats}"]
|
265
274
|
end
|
266
275
|
else
|
267
|
-
pata[-1]+=pats[1] #fex: /allo/
|
276
|
+
pata[-1] += pats[1] #fex: /allo/
|
268
277
|
end
|
269
278
|
end
|
270
|
-
if pata.size==1 and pata[0].kind_of?(String)
|
279
|
+
if pata.size == 1 and pata[0].kind_of?(String)
|
271
280
|
res = pata[0]
|
272
281
|
else
|
273
282
|
res = pata
|
@@ -0,0 +1,195 @@
|
|
1
|
+
class StringPattern
|
2
|
+
###############################################
|
3
|
+
# Analyze the pattern supplied and returns an object of Pattern structure including:
|
4
|
+
# min_length, max_length, symbol_type, required_data, excluded_data, data_provided, string_set, all_characters_set
|
5
|
+
###############################################
|
6
|
+
def StringPattern.analyze(pattern, silent: false)
|
7
|
+
#unless @cache[pattern.to_s].nil?
|
8
|
+
# return Pattern.new(@cache[pattern.to_s].min_length.clone, @cache[pattern.to_s].max_length.clone,
|
9
|
+
# @cache[pattern.to_s].symbol_type.clone, @cache[pattern.to_s].required_data.clone,
|
10
|
+
# @cache[pattern.to_s].excluded_data.clone, @cache[pattern.to_s].data_provided.clone,
|
11
|
+
# @cache[pattern.to_s].string_set.clone, @cache[pattern.to_s].all_characters_set.clone, @cache[pattern.to_s].unique.clone)
|
12
|
+
#end
|
13
|
+
return @cache[pattern.to_s].clone unless @cache[pattern.to_s].nil?
|
14
|
+
min_length, max_length, symbol_type = pattern.to_s.scan(/(\d+)-(\d+):(.+)/)[0]
|
15
|
+
if min_length.nil?
|
16
|
+
min_length, symbol_type = pattern.to_s.scan(/^!?(\d+):(.+)/)[0]
|
17
|
+
max_length = min_length
|
18
|
+
if min_length.nil?
|
19
|
+
puts "pattern argument not valid on StringPattern.generate: #{pattern.inspect}" unless silent
|
20
|
+
return pattern.to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
if symbol_type[-1] == "&"
|
24
|
+
symbol_type.chop!
|
25
|
+
unique = true
|
26
|
+
else
|
27
|
+
unique = false
|
28
|
+
end
|
29
|
+
|
30
|
+
symbol_type = "!" + symbol_type if pattern.to_s[0] == "!"
|
31
|
+
min_length = min_length.to_i
|
32
|
+
max_length = max_length.to_i
|
33
|
+
|
34
|
+
required_data = Array.new
|
35
|
+
excluded_data = Array.new
|
36
|
+
required = false
|
37
|
+
excluded = false
|
38
|
+
data_provided = Array.new
|
39
|
+
a = symbol_type
|
40
|
+
begin_provided = a.index("[")
|
41
|
+
excluded_end_tag = false
|
42
|
+
unless begin_provided.nil?
|
43
|
+
c = begin_provided + 1
|
44
|
+
until c == a.size or (a[c..c] == "]" and a[c..c + 1] != "]]")
|
45
|
+
if a[c..c + 1] == "]]"
|
46
|
+
data_provided.push("]")
|
47
|
+
c = c + 2
|
48
|
+
elsif a[c..c + 1] == "%%" and !excluded
|
49
|
+
data_provided.push("%")
|
50
|
+
c = c + 2
|
51
|
+
else
|
52
|
+
if a[c..c] == "/" and !excluded
|
53
|
+
if a[c..c + 1] == "//"
|
54
|
+
data_provided.push(a[c..c])
|
55
|
+
if required
|
56
|
+
required_data.push([a[c..c]])
|
57
|
+
end
|
58
|
+
c = c + 1
|
59
|
+
else
|
60
|
+
if !required
|
61
|
+
required = true
|
62
|
+
else
|
63
|
+
required = false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else
|
67
|
+
if required
|
68
|
+
required_data.push([a[c..c]])
|
69
|
+
else
|
70
|
+
if a[c..c] == "%"
|
71
|
+
if a[c..c + 1] == "%%" and excluded
|
72
|
+
excluded_data.push([a[c..c]])
|
73
|
+
c = c + 1
|
74
|
+
else
|
75
|
+
if !excluded
|
76
|
+
excluded = true
|
77
|
+
else
|
78
|
+
excluded = false
|
79
|
+
excluded_end_tag = true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
else
|
83
|
+
if excluded
|
84
|
+
excluded_data.push([a[c..c]])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
if excluded == false and excluded_end_tag == false
|
89
|
+
data_provided.push(a[c..c])
|
90
|
+
end
|
91
|
+
excluded_end_tag = false
|
92
|
+
end
|
93
|
+
c = c + 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
symbol_type = symbol_type[0..begin_provided].to_s + symbol_type[c..symbol_type.size].to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
required = false
|
100
|
+
required_symbol = ""
|
101
|
+
if symbol_type.include?("/")
|
102
|
+
symbol_type.chars.each { |stc|
|
103
|
+
if stc == "/"
|
104
|
+
if !required
|
105
|
+
required = true
|
106
|
+
else
|
107
|
+
required = false
|
108
|
+
end
|
109
|
+
else
|
110
|
+
if required
|
111
|
+
required_symbol += stc
|
112
|
+
end
|
113
|
+
end
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
national_set = @national_chars.chars
|
118
|
+
|
119
|
+
if symbol_type.include?("L")
|
120
|
+
alpha_set = ALPHA_SET_LOWER.clone + ALPHA_SET_CAPITAL.clone
|
121
|
+
elsif symbol_type.include?("x")
|
122
|
+
alpha_set = ALPHA_SET_LOWER.clone
|
123
|
+
if symbol_type.include?("X")
|
124
|
+
alpha_set = alpha_set + ALPHA_SET_CAPITAL.clone
|
125
|
+
end
|
126
|
+
elsif symbol_type.include?("X")
|
127
|
+
alpha_set = ALPHA_SET_CAPITAL.clone
|
128
|
+
else
|
129
|
+
alpha_set = []
|
130
|
+
end
|
131
|
+
if symbol_type.include?("T")
|
132
|
+
alpha_set = alpha_set + national_set
|
133
|
+
end
|
134
|
+
|
135
|
+
unless required_symbol.nil?
|
136
|
+
if required_symbol.include?("x")
|
137
|
+
required_data.push ALPHA_SET_LOWER.clone
|
138
|
+
end
|
139
|
+
if required_symbol.include?("X")
|
140
|
+
required_data.push ALPHA_SET_CAPITAL.clone
|
141
|
+
end
|
142
|
+
if required_symbol.include?("L")
|
143
|
+
required_data.push(ALPHA_SET_CAPITAL.clone + ALPHA_SET_LOWER.clone)
|
144
|
+
end
|
145
|
+
if required_symbol.include?("T")
|
146
|
+
required_data.push national_set
|
147
|
+
end
|
148
|
+
required_symbol = required_symbol.downcase
|
149
|
+
end
|
150
|
+
string_set = Array.new
|
151
|
+
|
152
|
+
all_characters_set = ALPHA_SET_CAPITAL.clone + ALPHA_SET_LOWER.clone + NUMBER_SET.clone + SPECIAL_SET.clone + data_provided + national_set
|
153
|
+
if symbol_type.include?("_")
|
154
|
+
unless symbol_type.include?("$")
|
155
|
+
string_set.push(" ")
|
156
|
+
end
|
157
|
+
if required_symbol.include?("_")
|
158
|
+
required_data.push([" "])
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
#symbol_type = symbol_type.downcase
|
163
|
+
|
164
|
+
if symbol_type.downcase.include?("x") or symbol_type.downcase.include?("l") or symbol_type.downcase.include?("t")
|
165
|
+
string_set = string_set + alpha_set
|
166
|
+
end
|
167
|
+
if symbol_type.downcase.include?("n")
|
168
|
+
string_set = string_set + NUMBER_SET
|
169
|
+
end
|
170
|
+
if symbol_type.include?("$")
|
171
|
+
string_set = string_set + SPECIAL_SET
|
172
|
+
end
|
173
|
+
if symbol_type.include?("*")
|
174
|
+
string_set = string_set + all_characters_set
|
175
|
+
end
|
176
|
+
if data_provided.size != 0
|
177
|
+
string_set = string_set + data_provided
|
178
|
+
end
|
179
|
+
unless required_symbol.empty?
|
180
|
+
if required_symbol.include?("n")
|
181
|
+
required_data.push NUMBER_SET.clone
|
182
|
+
end
|
183
|
+
if required_symbol.include?("$")
|
184
|
+
required_data.push SPECIAL_SET.clone
|
185
|
+
end
|
186
|
+
end
|
187
|
+
unless excluded_data.empty?
|
188
|
+
string_set = string_set - excluded_data.flatten
|
189
|
+
end
|
190
|
+
string_set.uniq!
|
191
|
+
@cache[pattern.to_s] = Pattern.new(min_length, max_length, symbol_type, required_data, excluded_data, data_provided,
|
192
|
+
string_set, all_characters_set, unique)
|
193
|
+
return @cache[pattern.to_s].clone
|
194
|
+
end
|
195
|
+
end
|