1
+ function data = parse_json(string )
2
+ % DATA = PARSE_JSON(string)
3
+ % This function parses a JSON string and returns a cell array with the
4
+ % parsed data. JSON objects are converted to structures and JSON arrays are
5
+ % converted to cell arrays.
6
+
7
+ % F. Glineur, 2009
8
+ % (inspired by the JSON parser by Joel Feenstra on MATLAB File Exchange
9
+ % (http://www.mathworks.com/matlabcentral/fileexchange/20565) but with
10
+ % faster handling of strings)
11
+
12
+ pos = 1 ;
13
+ len = length(string );
14
+ % String delimiters and escape characters are identified beforehand to improve speed
15
+ esc = regexp(string , ' ["\\ ]' ); index_esc = 1 ; len_esc = length(esc );
16
+
17
+ if pos <= len
18
+ switch (next_char )
19
+ case ' {'
20
+ data = parse_object ;
21
+ case ' ['
22
+ data = parse_array ;
23
+ otherwise
24
+ error_pos(' Outer level structure must be an object or an array' );
25
+ end
26
+ end
27
+
28
+ function object = parse_object
29
+ parse_char(' {' );
30
+ object = [];
31
+ if next_char ~= ' }'
32
+ while 1
33
+ str = parse_string ;
34
+ if isempty(str )
35
+ error_pos(' Name of value at position %d cannot be empty' );
36
+ end
37
+ parse_char(' :' );
38
+ val = parse_value ;
39
+ object.(valid_field(str )) = val ;
40
+ if next_char == ' }'
41
+ break ;
42
+ end
43
+ parse_char(' ,' );
44
+ end
45
+ end
46
+ parse_char(' }' );
47
+ end
48
+
49
+ function object = parse_array
50
+ parse_char(' [' );
51
+ object = cell(0 , 1 );
52
+ if next_char ~= ' ]'
53
+ while 1
54
+ val = parse_value ;
55
+ object{end + 1 } = val ;
56
+ if next_char == ' ]'
57
+ break ;
58
+ end
59
+ parse_char(' ,' );
60
+ end
61
+ end
62
+ parse_char(' ]' );
63
+ end
64
+
65
+ function parse_char(c )
66
+ skip_whitespace ;
67
+ if pos > len || string(pos ) ~= c
68
+ error_pos(sprintf(' Expected %c at position %% d' , c ));
69
+ else
70
+ pos = pos + 1 ;
71
+ skip_whitespace ;
72
+ end
73
+ end
74
+
75
+ function c = next_char
76
+ skip_whitespace ;
77
+ if pos > len
78
+ c = [];
79
+ else
80
+ c = string(pos );
81
+ end
82
+ end
83
+
84
+ function skip_whitespace
85
+ while pos <= len && isspace(string(pos ))
86
+ pos = pos + 1 ;
87
+ end
88
+ end
89
+
90
+ function str = parse_string
91
+ if string(pos ) ~= ' "'
92
+ error_pos(' String starting with " expected at position %d ' );
93
+ else
94
+ pos = pos + 1 ;
95
+ end
96
+ str = ' ' ;
97
+ while pos <= len
98
+ while index_esc <= len_esc && esc(index_esc ) < pos
99
+ index_esc = index_esc + 1 ;
100
+ end
101
+ if index_esc > len_esc
102
+ str = [str string(pos : end )];
103
+ pos = len + 1 ;
104
+ break ;
105
+ else
106
+ str = [str string(pos : esc(index_esc )-1 )];
107
+ pos = esc(index_esc );
108
+ end
109
+ switch string(pos )
110
+ case ' "'
111
+ pos = pos + 1 ;
112
+ return ;
113
+ case ' \'
114
+ if pos + 1 > len
115
+ error_pos(' End of file reached right after escape character' );
116
+ end
117
+ pos = pos + 1 ;
118
+ switch string(pos )
119
+ case {' "' ' \' ' /' }
120
+ str(end + 1 ) = string(pos );
121
+ pos = pos + 1 ;
122
+ case {' b' ' f' ' n' ' r' ' t' }
123
+ str(end + 1 ) = sprintf([' \' string(pos )]);
124
+ pos = pos + 1 ;
125
+ case ' u'
126
+ if pos + 4 > len
127
+ error_pos(' End of file reached in escaped unicode character' );
128
+ end
129
+ str(end + 1 : end + 6 ) = string(pos - 1 : pos + 4 );
130
+ pos = pos + 5 ;
131
+ end
132
+ otherwise % should never happen
133
+ str(end + 1 ) = string(pos );
134
+ pos = pos + 1 ;
135
+ end
136
+ end
137
+ error_pos(' End of file while expecting end of string' );
138
+ end
139
+
140
+ function num = parse_number
141
+ [num , one , err , delta ] = sscanf(string(pos : min(len ,pos + 20 )), ' %f ' , 1 ); % TODO : compare with json(pos:end)
142
+ if ~isempty(err )
143
+ error_pos(' Error reading number at position %d ' );
144
+ end
145
+ pos = pos + delta - 1 ;
146
+ end
147
+
148
+ function val = parse_value
149
+ switch (string(pos ))
150
+ case ' "'
151
+ val = parse_string ;
152
+ return ;
153
+ case ' ['
154
+ val = parse_array ;
155
+ return ;
156
+ case ' {'
157
+ val = parse_object ;
158
+ return ;
159
+ case {' -' ,' 0' ,' 1' ,' 2' ,' 3' ,' 4' ,' 5' ,' 6' ,' 7' ,' 8' ,' 9' }
160
+ val = parse_number ;
161
+ return ;
162
+ case ' t'
163
+ if pos + 3 <= len && strcmpi(string(pos : pos + 3 ), ' true' )
164
+ val = true ;
165
+ pos = pos + 4 ;
166
+ return ;
167
+ end
168
+ case ' f'
169
+ if pos + 4 <= len && strcmpi(string(pos : pos + 4 ), ' false' )
170
+ val = false ;
171
+ pos = pos + 5 ;
172
+ return ;
173
+ end
174
+ case ' n'
175
+ if pos + 3 <= len && strcmpi(string(pos : pos + 3 ), ' null' )
176
+ val = [];
177
+ pos = pos + 4 ;
178
+ return ;
179
+ end
180
+ end
181
+ error_pos(' Value expected at position %d ' );
182
+ end
183
+
184
+ function error_pos(msg )
185
+ poss = max(min([pos - 15 pos - 1 pos pos + 20 ],len ),1 );
186
+ if poss(3 ) == poss(2 )
187
+ poss(3 : 4 ) = poss(2 )+[0 - 1 ]; % display nothing after
188
+ end
189
+ msg = [sprintf(msg , pos ) ' : ... ' string(poss(1 ): poss(2 )) ' <error>' string(poss(3 ): poss(4 )) ' ... ' ];
190
+ error(' JSONparser:invalidFormat' ,msg );
191
+ end
192
+
193
+ function str = valid_field(str )
194
+ % From MATLAB doc: field names must begin with a letter, which may be
195
+ % followed by any combination of letters, digits, and underscores.
196
+ % Invalid characters will be converted to underscores, and the prefix
197
+ % "alpha_" will be added if first character is not a letter.
198
+ if ~isletter(str(1 ))
199
+ str = [' alpha_' str ];
200
+ end
201
+ str(~isletter(str ) & ~(' 0' <= str & str <= ' 9' )) = ' _' ;
202
+ end
203
+
204
+ end
0 commit comments