Analyse des tables avec des caractères unicode dans les variables de JSON avec Base SAS
j'ai eu un problème de parsing JSON avec unicode char dans vars. Donc, j'ai de la prochaine JSON (exemple):
{
"SASJSONExport":"1.0",
"SASTableData+TEST":[
{
"u041fu0435u0440u0435u043cu0435u043du043du0430u044f":2,
"u0421u0440u0435u0434u043du0435u0435":4,
"u0421u0442u0440u043eu043au0430":"u0427u0442u043eu002du0442u043eu0031"
},
{
"u041fu0435u0440u0435u043cu0435u043du043du0430u044f":2,
"u0421u0440u0435u0434u043du0435u0435":2,
"u0421u0442u0440u043eu043au0430":"u0427u0442u043eu002du0442u043eu0032"
},
{
"u041fu0435u0440u0435u043cu0435u043du043du0430u044f":1,
"u0421u0440u0435u0434u043du0435u0435":42,
"u0421u0442u0440u043eu043au0430":"u0427u0442u043eu002du0442u043eu0033"
}
]
}
Pour analyser le tableau de JSON-je utiliser SAS moteur:
libname jsonfl JSON fileref=injson ;
Le code plus décoder les caractères dans les cellules, mais le nom de vars ressemble manque de vals:
+--------------+---------------------------+------------+---------+---------+
| ordinal_root | ordinal_SASTableData_TEST | __________ | _______ | ______ |
+--------------+---------------------------+------------+---------+---------+
| 1 | 1 | 2 | 4 | Что-то1 |
| 1 | 2 | 2 | 2 | Что-то2 |
| 1 | 3 | 1 | 42 | Что-то3 |
+--------------+---------------------------+------------+---------+---------+
L'en-tête doit ressembler à ça:
+--------------+---------------------------+------------+---------+---------+
| ordinal_root | ordinal_SASTableData_TEST | Переменная | Среднее | Строка |
+--------------+---------------------------+------------+---------+---------+
J'ai donc décidé de remplacer les variables unicoded par des noms comme celui-ci DIM_N_
.
Et pour cela je dois trouver tout les chaînes, qui sont d'accord avec la prochaine regexp: /([swd]+)":/
Mais, pour obtenir des chaînes de json j'ai besoin de le configurer comme delim le prochain char '{','}','[',']',','
.
Mais si j'opte pour dlm, Je n'assemblerai plus json.
J'ai donc décidé de coller avant le char!--12--> définir comme dlm.
data delim;
infile injson lrecl=1073741823 nopad;
file delim;
input char1 $char1. @@;
if char1 in ('{','}','[',']',',') then
put '7E'x;
put char1 $CHAR1. @@;
run;
j'ai le novalid fichier json:
~
{"SASJSONExport":"1.0"~
,"SASTableData+TEST":~
[ ~
{"u0056u0061u0072":2~
,"u006du0065u0061u006e":4~
,"u004eu0061u006du0065":"u0073u006du0074u0068u0031"~
}~
, ~
{"u0056u0061u0072":2~
,"u006du0065u0061u006e":2~
,"u004eu0061u006du0065":"u0073u006du0074u0068u0032"~
}~
, ~
{"u0056u0061u0072":1~
,"u006du0065u0061u006e":42~
,"u004eu0061u006du0065":"u0073u006du0074u0068u0033"~
} ~
]~
}
comme prochaine étape, je vais analyser JSON et utiliser ~
comme délimiteur:
data transfer;
length column 00;
retain r;
infile delim delimiter='7E'x nopad;
input char1 : 00. @@;
r = prxparse('/([swd]+)":/');
pos = prxmatch(r,char1);
column = prxposn(r,1,char1);
n= _n_;
run;
Cela fonctionne... Mais je sens que ceux trop de mauvaises pratiques, et Il a des limites.
UPD1
Option,
options vAlidfmtname=long VALIDMEMNAME=extend VALIDVARNAME=any;
retour:
+--------------+---------------------------+----------------------------+---------+--------------+
| ordinal_root | ordinal_SASTableData_TEST | __________ | _______ | ______ |
+--------------+---------------------------+----------------------------+---------+--------------+
| 1 | 1 | авфа2 фвафв = фвыа - тфвыа | 4 | Что-то1 ,,,, |
| 1 | 2 | авфа2 фвафв = фвыа - тфвыа | 2 | Что-то2 |
| 1 | 3 | авфа2 фвафв = фвыа - тфвыа | 2017 | Что-то3 |
+--------------+---------------------------+----------------------------+---------+--------------+
Donc mes questions sont:
- puis-je décoder tout le fichier sans le
infile
déclaration? - puis-je utiliser
infile delimiter
, mais définir des options smth pour ne pas supprimer le délimiteur?
des critiques adéquates sont les bienvenues.
1 réponses
UPD
je suis arrivé à la solution sans avoir à éditer manuellement le fichier de mappage json, mais en utilisant un regex.
libname _all_ clear;
filename _all_ clear;
filename _PDFOUT temp;
filename _GSFNAME temp;
proc datasets lib=work kill memtype=data nolist; quit;
filename jsf '~/sasuser.v94/.json' encoding='utf-8';
data _null_;
file jsf;
length js varchar(*);
retain js;
input;
js=unicode(_infile_);
put js;
datalines;
{
"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"
}
]
}
;
run;
filename jsm '~/sasuser.v94/.json.map' encoding='utf-8';
libname jsd json fileref=jsf map=jsm automap=replace;
libname jsm json fileref=jsm;
data jsmm;
merge jsm.datasets jsm.datasets_variables;
by ordinal_DATASETS;
run;
proc sort data=jsmm; by ordinal_root ordinal_DATASETS; run;
data _null_;
set work.jsmm end=last;
if _N_=1 then do;
length s varchar(*) ds varchar(*);
retain s ds prx;
s='{"DATASETS":[';
ds='';
prx=prxparse('/[^_]/');
end;
if ds=dsname then s=s||',';
else do;
ds=dsname;
if _N_^=1 then s=s||']},';
s=cats(s,'{"DSNAME":"',ds,'","TABLEPATH":"',tablepath,'","VARIABLES":[');
end;
s=cats(s,'{"NAME":"',name,'","TYPE":"',type,'","PATH":"',path,'"');
if prxmatch(prx,name) > length(name) then
s=cats(s,',"LABEL":"',scan(path,-1,'/'),'"');
s=s||'}';
if last then do;
s=s||']}]}';
file jsm;
put s;
end;
run;
libname jsd json fileref=jsf map=jsm;
proc print data=jsd.SASTableData_TEST label noobs; run;
la première variante de La solution
c'est la solution quick'n'Dirty.
première préparation des données d'entrée:
libname _all_ clear;
filename _all_ clear;
filename jsf '~/sasuser.v94/.json' encoding='utf-8';
data _null_;
file jsf;
length js varchar(*);
input;
js=unicode(_infile_);
put js;
datalines;
{
"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"
}
]
}
;
run;
Le fichier de sortie .json
:
{
"SASJSONExport":"1.0",
"SASTableData+TEST": [
{
"Переменная":2,
"Среднее":4,
"Строка":"Что-то1"
},
{
"Переменная":2,
"Среднее":2,
"Строка":"Что-то2"
},
{
"Переменная":1,
"Среднее":42,
"Строка":"Что-то3"
}
]
}
puis créer le fichier de map json .json.map
:
filename jsmf '~/sasuser.v94/.json.map' encoding='utf-8';
libname jsm json fileref=jsf map=jsmf automap=create;
le .json.map
table des matières:
{
"DATASETS": [
{
"DSNAME": "root",
"TABLEPATH": "/root",
"VARIABLES": [
{
"NAME": "ordinal_root",
"TYPE": "ORDINAL",
"PATH": "/root"
},
{
"NAME": "SASJSONExport",
"TYPE": "CHARACTER",
"PATH": "/root/SASJSONExport",
"CURRENT_LENGTH": 3
}
]
},
{
"DSNAME": "SASTableData_TEST",
"TABLEPATH": "/root/SASTableData+TEST",
"VARIABLES": [
{
"NAME": "ordinal_root",
"TYPE": "ORDINAL",
"PATH": "/root"
},
{
"NAME": "ordinal_SASTableData_TEST",
"TYPE": "ORDINAL",
"PATH": "/root/SASTableData+TEST"
},
{
"NAME": "____________________",
"TYPE": "NUMERIC",
"PATH": "/root/SASTableData+TEST/Переменная"
},
{
"NAME": "______________",
"TYPE": "NUMERIC",
"PATH": "/root/SASTableData+TEST/Среднее"
},
{
"NAME": "____________",
"TYPE": "CHARACTER",
"PATH": "/root/SASTableData+TEST/Строка",
"CURRENT_LENGTH": 12
}
]
}
]
}
changeons un peu le fichier en supprimant la description de l'ensemble de données non nécessaires et en ajoutant des étiquettes:
{
"DATASETS": [
{
"DSNAME": "SASTableData_TEST",
"TABLEPATH": "/root/SASTableData+TEST",
"VARIABLES": [
{
"NAME": "ordinal_root",
"TYPE": "ORDINAL",
"PATH": "/root"
},
{
"NAME": "ordinal_SASTableData_TEST",
"TYPE": "ORDINAL",
"PATH": "/root/SASTableData+TEST"
},
{
"NAME": "____________________",
"TYPE": "NUMERIC",
"PATH": "/root/SASTableData+TEST/Переменная",
"LABEL": "Переменная"
},
{
"NAME": "______________",
"TYPE": "NUMERIC",
"PATH": "/root/SASTableData+TEST/Среднее",
"LABEL": "Среднее"
},
{
"NAME": "____________",
"TYPE": "CHARACTER",
"PATH": "/root/SASTableData+TEST/Строка",
"LABEL": "Строка",
"CURRENT_LENGTH": 12
}
]
}
]
}
Et essayez de nouveau:
libname jsd json fileref=jsf map=jsmf;
proc print data=jsd.SASTableData_TEST label noobs; run;
Le résultat:
+--------------+---------------------------+- ----------+---------+-----------+
| ordinal_root | ordinal_SASTableData_TEST | Переменная | Среднее | Строка |
+--------------+---------------------------+------------+---------+-----------+
| 1 | 1 | 2 | 4 | Что-то1 |
| 1 | 2 | 2 | 2 | Что-то2 |
| 1 | 3 | 1 | 42 | Что-то3 |
+--------------+---------------------------+------------+---------+-----------+
Tout ce qu'il a fait dans le SAS de l'Université de l'Édition.