1 // Package printf implements a parser for fmt.Printf-style format
4 // It parses verbs according to the following syntax:
6 // Letter -> 'a'-'z' | 'A'-'Z'
7 // Index -> '[' Numeric+ ']'
11 // Precision -> Numeric+ | Star
12 // Width -> Numeric+ | Star
14 // WidthAndPrecision -> Width '.' Precision
15 // WidthAndPrecision -> Width '.'
16 // WidthAndPrecision -> Width
17 // WidthAndPrecision -> '.' Precision
18 // WidthAndPrecision -> '.'
20 // Flag -> '+' | '-' | '#' | ' ' | '0'
21 // Verb -> Letter | '%'
23 // Input -> '%' [ Flag+ ] [ WidthAndPrecision ] [ Index ] Verb
33 // ErrInvalid is returned for invalid format strings or verbs.
34 var ErrInvalid = errors.New("invalid format string")
42 // Which value in the argument list the verb uses.
43 // -1 denotes the next argument,
44 // values > 0 denote explicit arguments.
45 // The value 0 denotes that no argument is consumed. This is the case for %%.
51 // Argument is an implicit or explicit width or precision.
52 type Argument interface {
56 // The Default value, when no width or precision is provided.
59 // Zero is the implicit zero value.
60 // This value may only appear for precisions in format strings like %6.f
63 // Star is a * value, which may either refer to the next argument (Index == -1) or an explicit argument.
64 type Star struct{ Index int }
66 // A Literal value, such as 6 in %6d.
69 func (Default) isArgument() {}
70 func (Zero) isArgument() {}
71 func (Star) isArgument() {}
72 func (Literal) isArgument() {}
74 // Parse parses f and returns a list of actions.
75 // An action may either be a literal string, or a Verb.
76 func Parse(f string) ([]interface{}, error) {
80 v, n, err := ParseVerb(f)
87 n := strings.IndexByte(f, '%')
89 out = append(out, f[:n])
101 func atoi(s string) int {
102 n, _ := strconv.Atoi(s)
106 // ParseVerb parses the verb at the beginning of f.
107 // It returns the verb, how much of the input was consumed, and an error, if any.
108 func ParseVerb(f string) (Verb, int, error) {
110 return Verb{}, 0, ErrInvalid
128 m := re.FindStringSubmatch(f)
130 return Verb{}, 0, ErrInvalid
134 Letter: []rune(m[verb])[0],
141 v.Width = Literal(atoi(m[width]))
142 } else if m[widthStar] != "" {
144 if m[widthIndex] != "" {
145 v.Width = Star{atoi(m[widthIndex])}
156 v.Precision = Default{}
160 v.Precision = Literal(atoi(m[prec]))
161 } else if m[precStar] != "" {
163 if m[precIndex] != "" {
164 v.Precision = Star{atoi(m[precIndex])}
166 v.Precision = Star{-1}
176 } else if m[verbIndex] != "" {
177 v.Value = atoi(m[verbIndex])
182 return v, len(m[0]), nil
188 index = `(?:\[([0-9]+)\])`
189 star = `((` + index + `)?\*)`
192 width = `(?:` + width1 + `|` + width2 + `)`
194 widthAndPrecision = `(?:(?:` + width + `)?(?:(\.)(?:` + precision + `)?)?)`
197 var re = regexp.MustCompile(`^%` + flags + widthAndPrecision + `?` + index + `?` + verb)