encoding/jsonpb: improve and fix unmarshaling of Duration

Change use of regular expression to manually parsing the value.

Allow value with + symbol in front, e.g. "+3s". Previous regex missed
this.

Do not allow values without numbers, e.g. "-s". Previous regex missed
this as well.

name                  old time/op    new time/op    delta
Unmarshal_Duration-4    1.96µs ± 0%    1.24µs ± 0%   ~     (p=1.000 n=1+1)

name                  old alloc/op   new alloc/op   delta
Unmarshal_Duration-4      703B ± 0%      512B ± 0%   ~     (p=1.000 n=1+1)

name                  old allocs/op  new allocs/op  delta
Unmarshal_Duration-4      20.0 ± 0%      17.0 ± 0%   ~     (p=1.000 n=1+1)

Change-Id: I4db58d70f55607213631c49d698ee6a048b5e094
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/170012
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/jsonpb/bench_test.go b/encoding/jsonpb/bench_test.go
new file mode 100644
index 0000000..eba4119
--- /dev/null
+++ b/encoding/jsonpb/bench_test.go
@@ -0,0 +1,23 @@
+// Copyright 2019 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 jsonpb_test
+
+import (
+	"testing"
+
+	"github.com/golang/protobuf/v2/encoding/jsonpb"
+	knownpb "github.com/golang/protobuf/v2/types/known"
+)
+
+func BenchmarkUnmarshal_Duration(b *testing.B) {
+	input := []byte(`"-123456789.123456789s"`)
+
+	for i := 0; i < b.N; i++ {
+		err := jsonpb.Unmarshal(&knownpb.Duration{}, input)
+		if err != nil {
+			b.Fatal(err)
+		}
+	}
+}