У меня возникла проблема с разбором JSON с unicode char в vars. Итак, у меня следующий JSON (пример):
{
"SASJSONExport":"1.0",
"SASTableData+TEST":[
{
"\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f":2,
"\u0421\u0440\u0435\u0434\u043d\u0435\u0435":4,
"\u0421\u0442\u0440\u043e\u043a\u0430":"\u0427\u0442\u043e\u002d\u0442\u043e\u0031"
},
{
"\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f":2,
"\u0421\u0440\u0435\u0434\u043d\u0435\u0435":2,
"\u0421\u0442\u0440\u043e\u043a\u0430":"\u0427\u0442\u043e\u002d\u0442\u043e\u0032"
},
{
"\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f":1,
"\u0421\u0440\u0435\u0434\u043d\u0435\u0435":42,
"\u0421\u0442\u0440\u043e\u043a\u0430":"\u0427\u0442\u043e\u002d\u0442\u043e\u0033"
}
]
}
Чтобы разобрать таблицу из JSON, я использую механизм SAS:
libname jsonfl JSON fileref=injson ;
Более высокий код расшифровывает символы в ячейках, но имя vars выглядит как недостающие vals:
+--------------+---------------------------+------------+---------+---------+
| ordinal_root | ordinal_SASTableData_TEST | __________ | _______ | ______ |
+--------------+---------------------------+------------+---------+---------+
| 1 | 1 | 2 | 4 | Что-то1 |
| 1 | 2 | 2 | 2 | Что-то2 |
| 1 | 3 | 1 | 42 | Что-то3 |
+--------------+---------------------------+------------+---------+---------+
Заголовок должен выглядеть так:
+--------------+---------------------------+------------+---------+---------+
| ordinal_root | ordinal_SASTableData_TEST | Переменная | Среднее | Строка |
+--------------+---------------------------+------------+---------+---------+
Итак, я решил заменить символы unicoded variables такими именами как DIM_N_
.
И для этого я должен найти все строки, которые согласуются со следующим regexp: /([\s\w\d\\]+)\"\:/
Но, чтобы получить строки из json, мне нужно установить как delim следующий char '{','}','[',']',','
.
Но если установить эти символы как dlm, я не буду собирать json снова.
Поэтому я решил вставить перед char ~
, чтобы установить его как dlm.
data delim;
infile injson lrecl=1073741823 nopad;
file delim;
input char1 $char1. @@;
if char1 in ('{','}','[',']',',') then
put '7E'x;
put char1 $CHAR1. @@;
run;
Я получил новый файл json:
~
{"SASJSONExport":"1.0"~
,"SASTableData+TEST":~
[ ~
{"\u0056\u0061\u0072":2~
,"\u006d\u0065\u0061\u006e":4~
,"\u004e\u0061\u006d\u0065":"\u0073\u006d\u0074\u0068\u0031"~
}~
, ~
{"\u0056\u0061\u0072":2~
,"\u006d\u0065\u0061\u006e":2~
,"\u004e\u0061\u006d\u0065":"\u0073\u006d\u0074\u0068\u0032"~
}~
, ~
{"\u0056\u0061\u0072":1~
,"\u006d\u0065\u0061\u006e":42~
,"\u004e\u0061\u006d\u0065":"\u0073\u006d\u0074\u0068\u0033"~
} ~
]~
}
Итак, в качестве следующего шага я разбираю JSON и использую ~
как разделитель:
data transfer;
length column $2000;
retain r;
infile delim delimiter='7E'x nopad;
input char1 : $4000. @@;
r = prxparse('/([\s\w\d\\]+)\"\:/');
pos = prxmatch(r,char1);
column = prxposn(r,1,char1);
n= _n_;
run;
Это работает... Но я чувствую, что это слишком плохие практики, и он имеет ограничения.
UPD1
Опция,
options vAlidfmtname=long VALIDMEMNAME=extend VALIDVARNAME=any;
Возврат:
+--------------+---------------------------+----------------------------+---------+--------------+
| ordinal_root | ordinal_SASTableData_TEST | __________ | _______ | ______ |
+--------------+---------------------------+----------------------------+---------+--------------+
| 1 | 1 | авфа2 фвафв = фвыа - тфвыа | 4 | Что-то1 ,,,, |
| 1 | 2 | авфа2 фвафв = фвыа - тфвыа | 2 | Что-то2 |
| 1 | 3 | авфа2 фвафв = фвыа - тфвыа | 2017 | Что-то3 |
+--------------+---------------------------+----------------------------+---------+--------------+
Итак, мои вопросы:
- Можно ли декодировать весь файл без инструкции
infile
? - Можно ли использовать
infile delimiter
, но установить smth опции, чтобы не удалять разделитель?
Адекватная критика приветствуется.