-
Notifications
You must be signed in to change notification settings - Fork 6
/
pad.go
226 lines (196 loc) · 5.08 KB
/
pad.go
1
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
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
package fileseq
import (
"fmt"
"regexp"
"strconv"
"strings"
)
type PadStyle int
const (
// Constants defining the style of padding to use
// when converting between padding characters ('#', '##', '@@@')
// and their equivalent numeric padding width
PadStyleHash1 PadStyle = 0 // '#' char == 1
PadStyleHash4 PadStyle = 1 // '#' char == 4
PadStyleDefault = PadStyleHash4
)
var (
defaultPadding paddingMapper
padders map[PadStyle]paddingMapper
)
func init() {
padders = map[PadStyle]paddingMapper{
PadStyleHash1: newSingleHashPad(),
PadStyleHash4: newMultiHashPad(),
}
defaultPadding = padders[PadStyleDefault]
}
// paddingMapper defines behavior for converting between
// padding characters and their pad width
type paddingMapper interface {
// Return all supported padding characters
AllChars() []string
// Return the padding string sequence representing a width
PaddingChars(int) string
// Return a width for a string of pad characters
PaddingCharsSize(string) int
}
// multiHashPad is a paddingMapper that uses a single # to
// represent a width of 4 (i.e. Katana)
type multiHashPad struct {
*paddingMap
}
func newMultiHashPad() multiHashPad {
padMap := &paddingMap{
charToSize: map[string]int{"#": 4, "@": 1},
defaultChar: "@",
}
return multiHashPad{padMap}
}
func (m multiHashPad) PaddingChars(pad int) string {
switch {
case pad <= 0:
return m.defaultChar
case pad%4 == 0:
return strings.Repeat("#", pad/4)
default:
return strings.Repeat("@", pad)
}
}
// singleHashPad is a paddingMapper that uses a single # to
// represent a width of 1 (i.e. Nuke)
type singleHashPad struct {
*paddingMap
}
func newSingleHashPad() singleHashPad {
padMap := &paddingMap{
charToSize: map[string]int{"#": 1, "@": 1},
defaultChar: "#",
}
return singleHashPad{padMap}
}
func (m singleHashPad) PaddingChars(pad int) string {
if pad <= 0 {
return m.defaultChar
}
return strings.Repeat(m.defaultChar, pad)
}
type paddingMap struct {
charToSize map[string]int
cachedKeys []string
defaultChar string
}
func (m *paddingMap) AllChars() []string {
if m.cachedKeys == nil {
m.cachedKeys = make([]string, len(m.charToSize))
i := 0
for k := range m.charToSize {
m.cachedKeys[i] = k
i++
}
}
return m.cachedKeys
}
func (m *paddingMap) PaddingCharsSize(chars string) int {
if len(chars) == 0 {
return 0
}
// udim is a fixed padding size
if udimPattern.MatchString(chars) {
return 4
}
// check for alternate padding syntax
var match []string
for _, rx := range []*regexp.Regexp{printfPattern, houdiniPattern} {
if match = rx.FindStringSubmatch(chars); len(match) == 0 {
continue
}
intVal, err := strconv.Atoi(match[1])
if err != nil || intVal < 1 {
return 1
}
return intVal
}
// standard pad chars
var size int
for _, char := range chars {
size += m.charToSize[string(char)]
}
return size
}
// PaddingChars returns the proper padding characters,
// given an amount of padding. Uses PadStyleDefault.
func PaddingChars(pad int) string {
return defaultPadding.PaddingChars(pad)
}
// PadFrameRange takes a frame range string and returns a
// new range with each number padded out with zeros to a given width
func PadFrameRange(frange string, pad int) string {
// We don't need to do anything if they gave us
// an invalid pad number
if pad < 2 {
return frange
}
size := strings.Count(frange, ",") + 1
parts := make([]string, size, size)
for i, part := range strings.Split(frange, ",") {
didMatch := false
for _, rx := range rangePatterns {
matched := rx.FindStringSubmatch(part)
if len(matched) == 0 {
continue
}
matched = matched[1:]
size = len(matched)
switch size {
case 1:
parts[i] = zfillString(matched[0], pad)
case 2:
parts[i] = fmt.Sprintf("%s-%s",
zfillString(matched[0], pad),
zfillString(matched[1], pad))
case 4:
parts[i] = fmt.Sprintf("%s-%s%s%s",
zfillString(matched[0], pad),
zfillString(matched[1], pad),
matched[2], matched[3])
default:
// No match. Try the next pattern
continue
}
// If we got here, we matched a case and can stop
// checking the rest of the patterns
didMatch = true
break
}
// If we didn't match one of our expected patterns
// then just take the original part and add it unmodified
if !didMatch {
parts = append(parts, part)
}
}
return strings.Join(parts, ",")
}
// Left pads a string to a given with, using "0".
// If the string begins with a negative "-" character, then
// padding is inserted between the "-" and the remaining characters.
func zfillString(src string, z int) string {
size := len(src)
if size >= z {
return src
}
fill := strings.Repeat("0", z-size)
if strings.HasPrefix(src, "-") {
return fmt.Sprintf("-%s%s", fill, src[1:])
}
return fmt.Sprintf("%s%s", fill, src)
}
// Left pads an int to a given with, using "0".
// If the string begins with a negative "-" character, then
// padding is inserted between the "-" and the remaining characters.
func zfillInt(src int, z int) string {
if z < 2 {
return strconv.Itoa(src)
}
return fmt.Sprintf(fmt.Sprintf("%%0%dd", z), src)
}