11package strparam
22
33import (
4+ "errors"
45 "fmt"
56 "strings"
67 "unicode/utf8"
78)
89
10+ // ParseWithName analyzes the pattern, split it into tokens. Saves the schema name.
11+ //
12+ // Iterate over the UTF-8 characters (with correct offset of bytes).
13+ func ParseWithName (name , exp string ) (* Pattern , error ) {
14+ return parse (name , exp )
15+ }
16+
917// Parse analyzes the pattern, split it into tokens.
1018//
1119// Iterate over the UTF-8 characters (with correct offset of bytes).
12- func Parse (in string ) (* PatternSchema , error ) {
20+ func Parse (exp string ) (* Pattern , error ) {
21+ return parse ("" , exp )
22+ }
23+
24+ func parse (patternName , exp string ) (* Pattern , error ) {
25+ if exp == "" {
26+ return nil , errors .New ("expression should not is empty" )
27+ }
28+
1329 tokens := getlistTokens ()
1430 defer putlistTokens (tokens )
1531
1632 // end and start of parameter positions in bytes
1733 var start , end int = 0 , 0
18- // current mode
19- var mode TokenMode
34+ // current mode (initial as Pattern)
35+ var mode TokenMode = CONST
2036 // is flag of start char of input string
2137 var EOF bool
2238 // number of parameters
2339 var numParams int
2440
25- // end of input string
41+ // start of input string
2642 tokens = append (tokens , Token {
27- Mode : BEGINLINE ,
43+ Mode : START ,
2844 })
2945
3046 // current UTF-8 character in a word
3147 var char rune
3248
3349 // w - character width in bytes
34- for i , w := 0 , 0 ; i < len (in ); i += w {
35- char , w = utf8 .DecodeRuneInString (in [i :])
36- EOF = i == len (in )- 1
50+ for i , w := 0 , 0 ; i < len (exp ); i += w {
51+ char , w = utf8 .DecodeRuneInString (exp [i :])
52+ EOF = i == len (exp )- 1
3753
3854 switch char {
3955 case DefaultStartParam :
4056
4157 // invalid input string if after end border of parameter got new parameter
42- if i - end == 0 {
58+ if i > 0 && i - end == 0 {
4359 return nil , fmt .Errorf ("should be a pattern between the parameters, pos %d" , i )
4460 }
4561
46- tokens = append (tokens , Token {
47- Mode : PATTERN ,
48- Len : i - end ,
49- Raw : in [end :i ],
50- })
62+ if i - end > 0 {
63+ // skip empty pattern
64+ // - at beginning of the input string the parameter
65+ tokens = append (tokens , Token {
66+ Mode : CONST ,
67+ Len : i - end ,
68+ Raw : exp [end :i ],
69+ })
70+ }
5171
5272 mode = PARAMETER
5373 start = i // sets start position of parameter
@@ -64,10 +84,10 @@ func Parse(in string) (*PatternSchema, error) {
6484
6585 tokens = append (tokens , Token {
6686 Mode : PARAMETER ,
67- Raw : in [start : i + 1 ],
87+ Raw : exp [start : i + 1 ],
6888 })
6989
70- mode = PATTERN
90+ mode = CONST
7191 end , start = i + 1 , i + 1 // zeroing positions
7292 numParams ++
7393 }
@@ -78,36 +98,47 @@ func Parse(in string) (*PatternSchema, error) {
7898 return nil , fmt .Errorf ("parameter was not closed, pos %d" , i )
7999 }
80100
81- if mode == PATTERN {
101+ if mode == CONST {
82102 // if exists chars after closed parameter
83103 if i + 1 - end > 0 {
84104 tokens = append (tokens , Token {
85- Mode : PATTERN ,
105+ Mode : CONST ,
86106 Len : i + 1 - end ,
87- Raw : in [end : i + 1 ],
107+ Raw : exp [end : i + 1 ],
88108 })
89109 }
90110 }
91111 }
92112 }
93113
94- // start of input string
114+ // end of input string
95115 tokens = append (tokens , Token {
96- Mode : ENDLINE ,
116+ Mode : END ,
117+ Raw : patternName ,
97118 })
98119
99- return & PatternSchema {
100- Pattern : in ,
120+ return & Pattern {
101121 Tokens : tokens ,
102122 NumParams : numParams ,
103123 }, nil
104124}
105125
106126// Lookup returns list params if input string matched to schema.
107- func (s * PatternSchema ) Lookup (in string ) (bool , Params ) {
127+ //
128+ // NOTE: nothing (empty list of tokens) not matches to anything.
129+ func (s * Pattern ) Lookup (in string ) (bool , Params ) {
130+ if s == nil {
131+ return false , nil
132+ }
133+
108134 params := getListParams ()
109135 defer putListParams (params )
110136
137+ if len (s .Tokens ) == 0 {
138+ // nothing not matches to anything
139+ return false , nil
140+ }
141+
111142 // this is the sum of the lengths of the patterns and found value of parameters
112143 var offset int
113144
@@ -117,12 +148,9 @@ func (s *PatternSchema) Lookup(in string) (bool, Params) {
117148 }
118149
119150 switch t .Mode {
120- case BEGINLINE :
121- case ENDLINE :
122- if offset < len (in ) {
123- // have tail without pattern
124- return false , nil
125- }
151+ case START :
152+ case END :
153+ goto exitloop
126154 case PARAMETER_PARSED :
127155 params = append (params , Param {
128156 Name : t .ParamName (),
@@ -132,13 +160,13 @@ func (s *PatternSchema) Lookup(in string) (bool, Params) {
132160 case PARAMETER :
133161 _next := s .Tokens [num + 1 ]
134162 switch _next .Mode {
135- case ENDLINE :
163+ case END :
136164 params = append (params , Param {
137165 Name : t .ParamName (),
138166 Value : in [offset :],
139167 })
140168 offset += len (in ) - offset
141- case PATTERN :
169+ case CONST :
142170 if found := strings .Index (in [offset :], _next .Raw ); found > - 1 {
143171 params = append (params , Param {
144172 Name : t .ParamName (),
@@ -152,28 +180,57 @@ func (s *PatternSchema) Lookup(in string) (bool, Params) {
152180 default :
153181 return false , nil
154182 }
155- case PATTERN :
183+ case CONST :
156184 if in [offset :offset + t .Len ] == t .Raw {
157185 // add the length of the pattern
158186 offset += t .Len
159187 } else {
188+ // forced return because pattern is not matched
160189 return false , nil
161190 }
162191 }
163192 }
164193
194+ exitloop:
195+
196+ // offset did not seeking to end of by input value
197+ if len (in ) != offset {
198+ return false , nil
199+ }
200+
201+ // received an unexpected number of parameters
165202 if len (params ) != s .NumParams {
166203 return false , nil
167204 }
205+
168206 return true , params
169207}
170208
171- type PatternSchema struct {
172- Pattern string
173- Tokens []Token
209+ type Pattern struct {
210+ Tokens Tokens
174211 NumParams int
175212}
176213
214+ // String returns schema of pattern.
215+ func (s Pattern ) String () string {
216+ return s .Tokens .String ()
217+ }
218+
219+ // Name returns name of pattern (by end token if sets).
220+ func (s Pattern ) Name () string {
221+ if s .Tokens == nil {
222+ return ""
223+ }
224+ if len (s .Tokens ) <= 1 {
225+ return ""
226+ }
227+ endToken := s .Tokens [len (s .Tokens )- 1 ]
228+ if endToken .Mode != END {
229+ return ""
230+ }
231+ return endToken .Raw
232+ }
233+
177234type Param struct {
178235 Name string
179236 Value string
0 commit comments