// Copyright 2018 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package jsonimport ()// parseNumber reads the given []byte for a valid JSON number. If it is valid,// it returns the number of bytes. Parsing logic follows the definition in// https://tools.ietf.org/html/rfc7159#section-6, and is based off// encoding/json.isValidNumber function.func ( []byte) (int, bool) {varint := iflen() == 0 {return0, false }// Optional -if [0] == '-' { = [1:] ++iflen() == 0 {return0, false } }// Digitsswitch {case [0] == '0': = [1:] ++case'1' <= [0] && [0] <= '9': = [1:] ++forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] ++ }default:return0, false }// . followed by 1 or more digits.iflen() >= 2 && [0] == '.' && '0' <= [1] && [1] <= '9' { = [2:] += 2forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] ++ } }// e or E followed by an optional - or + and // 1 or more digits.iflen() >= 2 && ([0] == 'e' || [0] == 'E') { = [1:] ++if [0] == '+' || [0] == '-' { = [1:] ++iflen() == 0 {return0, false } }forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] ++ } }// Check that next byte is a delimiter or it is at the end.if < len() && isNotDelim([]) {return0, false }return , true}// numberParts is the result of parsing out a valid JSON number. It contains// the parts of a number. The parts are used for integer conversion.typenumberPartsstruct {negboolintp []bytefrac []byteexp []byte}// parseNumber constructs numberParts from given []byte. The logic here is// similar to consumeNumber above with the difference of having to construct// numberParts. The slice fields in numberParts are subslices of the input.func ( []byte) (numberParts, bool) {varboolvar []bytevar []bytevar []byte := iflen() == 0 {returnnumberParts{}, false }// Optional -if [0] == '-' { = true = [1:]iflen() == 0 {returnnumberParts{}, false } }// Digitsswitch {case [0] == '0':// Skip first 0 and no need to store. = [1:]case'1' <= [0] && [0] <= '9': = := 1 = [1:]forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] ++ } = [:]default:returnnumberParts{}, false }// . followed by 1 or more digits.iflen() >= 2 && [0] == '.' && '0' <= [1] && [1] <= '9' { = [1:] := 1 = [2:]forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] ++ } = [:] }// e or E followed by an optional - or + and // 1 or more digits.iflen() >= 2 && ([0] == 'e' || [0] == 'E') { = [1:] = := 0if [0] == '+' || [0] == '-' { = [1:] ++iflen() == 0 {returnnumberParts{}, false } }forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] ++ } = [:] }returnnumberParts{neg: ,intp: ,frac: bytes.TrimRight(, "0"), // Remove unnecessary 0s to the right.exp: , }, true}// normalizeToIntString returns an integer string in normal form without the// E-notation for given numberParts. It will return false if it is not an// integer or if the exponent exceeds than max/min int value.func ( numberParts) (string, bool) { := len(.intp) := len(.frac)if == 0 && == 0 {return"0", true }varintiflen(.exp) > 0 { , := strconv.ParseInt(string(.exp), 10, 32)if != nil {return"", false } = int() }var []byteif >= 0 {// For positive E, shift fraction digits into integer part and also pad // with zeroes as needed.// If there are more digits in fraction than the E value, then the // number is not an integer.if > {return"", false }// Make sure resulting digits are within max value limit to avoid // unnecessarily constructing a large byte slice that may simply fail // later on.const = 20// Max uint64 value has 20 decimal digits.if + > {return"", false }// Set cap to make a copy of integer part when appended. = .intp[:len(.intp):len(.intp)] = append(, .frac...)for := 0; < -; ++ { = append(, '0') } } else {// For negative E, shift digits in integer part out.// If there are fractions, then the number is not an integer.if > 0 {return"", false }// index is where the decimal point will be after adjusting for negative // exponent. := + if < 0 {return"", false } = .intp// If any of the digits being shifted to the right of the decimal point // is non-zero, then the number is not an integer.for := ; < ; ++ {if [] != '0' {return"", false } } = [:] }if .neg {return"-" + string(), true }returnstring(), true}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)