12
12
namespace Ahc \Json ;
13
13
14
14
/**
15
- * JSON comment stripper.
15
+ * JSON comment and trailing comma stripper.
16
16
*
17
17
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
18
18
*/
19
19
class Comment
20
20
{
21
21
/** @var int The current index being scanned */
22
- protected $ index = -1 ;
22
+ protected $ index = -1 ;
23
23
24
24
/** @var bool If current char is within a string */
25
- protected $ inStr = false ;
25
+ protected $ inStr = false ;
26
26
27
27
/** @var int Lines of comments 0 = no comment, 1 = single line, 2 = multi lines */
28
28
protected $ comment = 0 ;
29
29
30
+ /** @var int Holds the backtace position of a possibly trailing comma */
31
+ protected $ commaPos = -1 ;
32
+
30
33
/**
31
34
* Strip comments from JSON string.
32
35
*
@@ -36,7 +39,7 @@ class Comment
36
39
*/
37
40
public function strip ($ json )
38
41
{
39
- if (!\preg_match ('%\/(\/|\*)% ' , $ json )) {
42
+ if (!\preg_match ('%\/(\/|\*)% ' , $ json ) && ! \preg_match ( ' /,\s*(\}|\])/ ' , $ json ) ) {
40
43
return $ json ;
41
44
}
42
45
@@ -59,6 +62,8 @@ protected function doStrip($json)
59
62
while (isset ($ json [++$ this ->index ])) {
60
63
list ($ prev , $ char , $ next ) = $ this ->getSegments ($ json );
61
64
65
+ $ return = $ this ->checkTrail ($ char , $ return );
66
+
62
67
if ($ this ->inStringOrCommentEnd ($ prev , $ char , $ char . $ next )) {
63
68
$ return .= $ char ;
64
69
@@ -85,9 +90,31 @@ protected function getSegments($json)
85
90
];
86
91
}
87
92
88
- protected function inStringOrCommentEnd ($ prev , $ char , $ charnext )
93
+ protected function checkTrail ($ char , $ json )
94
+ {
95
+ if ($ char === ', ' || $ this ->commaPos === -1 ) {
96
+ $ this ->commaPos = $ this ->commaPos + ($ char === ', ' ? 1 : 0 );
97
+
98
+ return $ json ;
99
+ }
100
+
101
+ if (\ctype_digit ($ char ) || \strpbrk ($ char , '"tfn{[ ' )) {
102
+ $ this ->commaPos = -1 ;
103
+ } elseif ($ char === '] ' || $ char === '} ' ) {
104
+ $ pos = \strlen ($ json ) - $ this ->commaPos - 1 ;
105
+ $ json = \substr ($ json , 0 , $ pos ) . \ltrim (\substr ($ json , $ pos ), ', ' );
106
+
107
+ $ this ->commaPos = -1 ;
108
+ } else {
109
+ $ this ->commaPos += 1 ;
110
+ }
111
+
112
+ return $ json ;
113
+ }
114
+
115
+ protected function inStringOrCommentEnd ($ prev , $ char , $ next )
89
116
{
90
- return $ this ->inString ($ char , $ prev ) || $ this ->inCommentEnd ($ charnext );
117
+ return $ this ->inString ($ char , $ prev ) || $ this ->inCommentEnd ($ next );
91
118
}
92
119
93
120
protected function inString ($ char , $ prev )
@@ -99,19 +126,19 @@ protected function inString($char, $prev)
99
126
return $ this ->inStr ;
100
127
}
101
128
102
- protected function inCommentEnd ($ charnext )
129
+ protected function inCommentEnd ($ next )
103
130
{
104
131
if (!$ this ->inStr && 0 === $ this ->comment ) {
105
- $ this ->comment = $ charnext === '// ' ? 1 : ($ charnext === '/* ' ? 2 : 0 );
132
+ $ this ->comment = $ next === '// ' ? 1 : ($ next === '/* ' ? 2 : 0 );
106
133
}
107
134
108
135
return 0 === $ this ->comment ;
109
136
}
110
137
111
- protected function hasCommentEnded ($ char , $ charnext )
138
+ protected function hasCommentEnded ($ char , $ next )
112
139
{
113
140
$ singleEnded = $ this ->comment === 1 && $ char == "\n" ;
114
- $ multiEnded = $ this ->comment === 2 && $ charnext == '*/ ' ;
141
+ $ multiEnded = $ this ->comment === 2 && $ next == '*/ ' ;
115
142
116
143
if ($ singleEnded || $ multiEnded ) {
117
144
$ this ->comment = 0 ;
0 commit comments