1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
9 // lower(c) is a lower-case letter if and only if
10 // c is either that lower-case letter or the equivalent upper-case letter.
11 // Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'.
12 // Note that lower of non-letters can produce other non-letters.
13 func lower(c
byte) byte {
14 return c |
('x' - 'X')
17 // ErrRange indicates that a value is out of range for the target type.
18 var ErrRange
= errors
.New("value out of range")
20 // ErrSyntax indicates that a value does not have the right syntax for the target type.
21 var ErrSyntax
= errors
.New("invalid syntax")
23 // A NumError records a failed conversion.
24 type NumError
struct {
25 Func
string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat, ParseComplex)
26 Num
string // the input
27 Err error
// the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
30 func (e
*NumError
) Error() string {
31 return "strconv." + e
.Func
+ ": " + "parsing " + Quote(e
.Num
) + ": " + e
.Err
.Error()
34 func (e
*NumError
) Unwrap() error
{ return e
.Err
}
36 func syntaxError(fn
, str
string) *NumError
{
37 return &NumError
{fn
, str
, ErrSyntax
}
40 func rangeError(fn
, str
string) *NumError
{
41 return &NumError
{fn
, str
, ErrRange
}
44 func baseError(fn
, str
string, base
int) *NumError
{
45 return &NumError
{fn
, str
, errors
.New("invalid base " + Itoa(base
))}
48 func bitSizeError(fn
, str
string, bitSize
int) *NumError
{
49 return &NumError
{fn
, str
, errors
.New("invalid bit size " + Itoa(bitSize
))}
52 const intSize
= 32 << (^uint(0) >> 63)
54 // IntSize is the size in bits of an int or uint value.
55 const IntSize
= intSize
57 const maxUint64
= 1<<64 - 1
59 // ParseUint is like ParseInt but for unsigned numbers.
61 // A sign prefix is not permitted.
62 func ParseUint(s
string, base
int, bitSize
int) (uint64, error
) {
63 const fnParseUint
= "ParseUint"
66 return 0, syntaxError(fnParseUint
, s
)
73 case 2 <= base
&& base
<= 36:
74 // valid base; nothing to do
77 // Look for octal, hex prefix.
81 case len(s
) >= 3 && lower(s
[1]) == 'b':
84 case len(s
) >= 3 && lower(s
[1]) == 'o':
87 case len(s
) >= 3 && lower(s
[1]) == 'x':
97 return 0, baseError(fnParseUint
, s0
, base
)
102 } else if bitSize
< 0 || bitSize
> 64 {
103 return 0, bitSizeError(fnParseUint
, s0
, bitSize
)
106 // Cutoff is the smallest number such that cutoff*base > maxUint64.
107 // Use compile-time constants for common cases.
111 cutoff
= maxUint64
/10 + 1
113 cutoff
= maxUint64
/16 + 1
115 cutoff
= maxUint64
/uint64(base
) + 1
118 maxVal
:= uint64(1)<<uint(bitSize
) - 1
122 for _
, c
:= range []byte(s
) {
125 case c
== '_' && base0
:
128 case '0' <= c
&& c
<= '9':
130 case 'a' <= lower(c
) && lower(c
) <= 'z':
131 d
= lower(c
) - 'a' + 10
133 return 0, syntaxError(fnParseUint
, s0
)
137 return 0, syntaxError(fnParseUint
, s0
)
142 return maxVal
, rangeError(fnParseUint
, s0
)
147 if n1
< n || n1
> maxVal
{
149 return maxVal
, rangeError(fnParseUint
, s0
)
154 if underscores
&& !underscoreOK(s0
) {
155 return 0, syntaxError(fnParseUint
, s0
)
161 // ParseInt interprets a string s in the given base (0, 2 to 36) and
162 // bit size (0 to 64) and returns the corresponding value i.
164 // The string may begin with a leading sign: "+" or "-".
166 // If the base argument is 0, the true base is implied by the string's
167 // prefix following the sign (if present): 2 for "0b", 8 for "0" or "0o",
168 // 16 for "0x", and 10 otherwise. Also, for argument base 0 only,
169 // underscore characters are permitted as defined by the Go syntax for
172 // The bitSize argument specifies the integer type
173 // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
174 // correspond to int, int8, int16, int32, and int64.
175 // If bitSize is below 0 or above 64, an error is returned.
177 // The errors that ParseInt returns have concrete type *NumError
178 // and include err.Num = s. If s is empty or contains invalid
179 // digits, err.Err = ErrSyntax and the returned value is 0;
180 // if the value corresponding to s cannot be represented by a
181 // signed integer of the given size, err.Err = ErrRange and the
182 // returned value is the maximum magnitude integer of the
183 // appropriate bitSize and sign.
184 func ParseInt(s
string, base
int, bitSize
int) (i
int64, err error
) {
185 const fnParseInt
= "ParseInt"
188 return 0, syntaxError(fnParseInt
, s
)
191 // Pick off leading sign.
196 } else if s
[0] == '-' {
201 // Convert unsigned and check range.
203 un
, err
= ParseUint(s
, base
, bitSize
)
204 if err
!= nil && err
.(*NumError
).Err
!= ErrRange
{
205 err
.(*NumError
).Func
= fnParseInt
206 err
.(*NumError
).Num
= s0
214 cutoff
:= uint64(1 << uint(bitSize
-1))
215 if !neg
&& un
>= cutoff
{
216 return int64(cutoff
- 1), rangeError(fnParseInt
, s0
)
218 if neg
&& un
> cutoff
{
219 return -int64(cutoff
), rangeError(fnParseInt
, s0
)
228 // Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.
229 func Atoi(s
string) (int, error
) {
230 const fnAtoi
= "Atoi"
233 if intSize
== 32 && (0 < sLen
&& sLen
< 10) ||
234 intSize
== 64 && (0 < sLen
&& sLen
< 19) {
235 // Fast path for small integers that fit int type.
237 if s
[0] == '-' || s
[0] == '+' {
240 return 0, &NumError
{fnAtoi
, s0
, ErrSyntax
}
245 for _
, ch
:= range []byte(s
) {
248 return 0, &NumError
{fnAtoi
, s0
, ErrSyntax
}
258 // Slow path for invalid, big, or underscored integers.
259 i64
, err
:= ParseInt(s
, 10, 0)
260 if nerr
, ok
:= err
.(*NumError
); ok
{
266 // underscoreOK reports whether the underscores in s are allowed.
267 // Checking them in this one function lets all the parsers skip over them simply.
268 // Underscore must appear only between digits or between a base prefix and a digit.
269 func underscoreOK(s
string) bool {
270 // saw tracks the last character (class) we saw:
271 // ^ for beginning of number,
272 // 0 for a digit or base prefix,
273 // _ for an underscore,
274 // ! for none of the above.
279 if len(s
) >= 1 && (s
[0] == '-' || s
[0] == '+') {
283 // Optional base prefix.
285 if len(s
) >= 2 && s
[0] == '0' && (lower(s
[1]) == 'b' ||
lower(s
[1]) == 'o' ||
lower(s
[1]) == 'x') {
287 saw
= '0' // base prefix counts as a digit for "underscore as digit separator"
288 hex
= lower(s
[1]) == 'x'
292 for ; i
< len(s
); i
++ {
293 // Digits are always okay.
294 if '0' <= s
[i
] && s
[i
] <= '9' || hex
&& 'a' <= lower(s
[i
]) && lower(s
[i
]) <= 'f' {
298 // Underscore must follow digit.
306 // Underscore must also be followed by digit.
310 // Saw non-digit, non-underscore.