1
1
package normalizer
2
2
3
3
import (
4
+ "fmt"
4
5
"strconv"
5
6
"unicode/utf8"
6
7
)
@@ -18,7 +19,7 @@ func unquoteSingle(s string) (string, error) {
18
19
}
19
20
quote := s [0 ]
20
21
if quote != s [n - 1 ] {
21
- return "" , strconv . ErrSyntax
22
+ return "" , fmt . Errorf ( "string does not begin and end with a quote" )
22
23
}
23
24
s = s [1 : len (s )- 1 ]
24
25
@@ -33,6 +34,7 @@ func unquoteSingle(s string) (string, error) {
33
34
return s , nil
34
35
}
35
36
}
37
+ s = replaceEscapedMaybe (s , '0' , '\x00' )
36
38
37
39
var runeTmp [utf8 .UTFMax ]byte
38
40
buf := make ([]byte , 0 , 3 * len (s )/ 2 ) // Try to avoid more allocations.
@@ -62,6 +64,42 @@ func contains(s string, c byte) bool {
62
64
return false
63
65
}
64
66
67
+ // replaceEscapedMaybe returns a copy of s with "\\old[^0-9]" replaced by new.
68
+ func replaceEscapedMaybe (s string , old , new rune ) string {
69
+ var runeTmp [utf8 .UTFMax ]byte
70
+ n := utf8 .EncodeRune (runeTmp [:], new )
71
+
72
+ lastCp := 0
73
+ var buf []byte
74
+ for i , w := 0 , 0 ; i < len (s ); i += w {
75
+ r1 , w1 := utf8 .DecodeRuneInString (s [i :])
76
+ w = w1
77
+ if r1 == '\\' { // find sequence \\old[^0-9]
78
+ r2 , w2 := utf8 .DecodeRuneInString (s [i + w1 :])
79
+ if r2 == old {
80
+ r3 , _ := utf8 .DecodeRuneInString (s [i + w1 + w2 :])
81
+ if 0 > r3 || r3 > 9 { // not a number after "\\old"
82
+ w += w2
83
+ if len (buf ) == 0 {
84
+ buf = make ([]byte , 0 , 3 * len (s )/ 2 )
85
+ }
86
+ buf = append (buf , []byte (s [lastCp :i ])... )
87
+ buf = append (buf , runeTmp [:n ]... )
88
+ lastCp = i + w
89
+ }
90
+ }
91
+ }
92
+ }
93
+ if lastCp == 0 {
94
+ return s
95
+ }
96
+
97
+ if 0 < lastCp && lastCp < len (s ) {
98
+ return string (append (buf , []byte (s [lastCp :len (s )])... ))
99
+ }
100
+ return string (buf )
101
+ }
102
+
65
103
const lowerhex = "0123456789abcdef"
66
104
67
105
// quoteSingle is the same as strconv.Quote, but uses ' as a quote.
0 commit comments