在 utf-8 SAS 中上传 latin1 文件时出现问题
Problem uploading a latin1 file in a utf-8 SAS
在带有 SAS 和 ENCODING=UTF-8 的 Linux 系统上,我有这个文件:
more provab.txt
▒00CC00 ▒00CC00 S012016-10-04
▒00CC00 ▒00CC00 S012021-10-20
xxd provab.txt
0000000: b130 3043 4330 3020 2020 b130 3043 4330 .00CC00 .00CC0
0000010: 3020 2020 5330 3132 3031 362d 3130 2d30 0 S012016-10-0
0000020: 3420 0ab1 3030 4343 3030 2020 20b1 3030 4 ..00CC00 .00
0000030: 4343 3030 2020 2053 3031 3230 3231 2d31 CC00 S012021-1
0000040: 302d 3230 200a 0-20 .
file -i provab.txt
provab.txt: text/plain; charset=iso-8859-1
如果我在没有设置编码的情况下将其加载到 SAS 中:
Filename inp "/mypath/provab.txt" ;
Data work.current_file;
Infile inp lrecl=33 DSD MISSOVER PAD firstObs=1;
Attrib campo_1 length=
format=$char10. informat=$char10. ;
Attrib campo_2 length=
format=$char10. informat=$char10. ;
Attrib campo_3 length=
format=$char3. informat=$char3. ;
Attrib chr_data length=
format=$char10. informat=$char10. ;
Input
@1 campo_1 $char10.
@11 campo_2 $char10.
@21 campo_3 $char3.
@24 chr_data $char10.
;
Run;
我得到:
如果我设置ENCODING= LATIN1
:
Filename inp "/mypath/provab.txt"
ENCODING= LATIN1
;
Data work.current_file;
Infile inp lrecl=33 DSD MISSOVER PAD firstObs=1;
Attrib campo_1 length=
format=$char10. informat=$char10. ;
Attrib campo_2 length=
format=$char10. informat=$char10. ;
Attrib campo_3 length=
format=$char3. informat=$char3. ;
Attrib chr_data length=
format=$char10. informat=$char10. ;
Input
@1 campo_1 $char10.
@11 campo_2 $char10.
@21 campo_3 $char3.
@24 chr_data $char10.
;
Run;
我得到:
如您所见,campo_1
和 campo2
显示正确,但每个“奇怪”字符都意味着其余字段发生了变化。
例如chr_date field
,被移动了2个字符。
我用 encoding='iso-8859-1'
也得到相同的结果。
并且 iconv -f ISO-8859-1 -t UTF-8 provab.txt >provau.txt
和加载 provau.txt
我也遇到同样的异常。
我该如何解决?
根据@GiacomoCatenazzi 的评论,我猜想当您提供编码时,加载程序首先进行字符集转换,然后才将数据拆分为字段。但是由于非 ascii Latin1 字符在 UTF-8 中被转换为 2 个字节,转换打破了固定大小的字段格式。
这意味着您必须进行重要的预处理:
- 将每一行拆分为固定大小的字段
- 将每个字段转换为 UTF-8 字符集
- 用保持原始宽度的填充将字段组合回去。
这对于 Python 脚本来说是微不足道的,可能可以用 awk 来完成,但恕我直言,您不会找到这样的产品。
根据 Joop Eggen 和其他人的评论和回答,我使用 SAS 函数 tranwrd
在 加载文件后解决了我的问题。
这给出了期望的结果:
Filename inp "/mypath/provab.txt";
Data work.current_file;
Infile inp lrecl=33 DSD MISSOVER PAD firstObs=1;
Attrib campo_1 length=
format=$char10. informat=$char10. ;
Attrib campo_2 length=
format=$char10. informat=$char10. ;
Attrib campo_3 length=
format=$char3. informat=$char3. ;
Attrib chr_data length=
format=$char10. informat=$char10. ;
Input
@1 campo_1 $char10.
@11 campo_2 $char10.
@21 campo_3 $char3.
@24 chr_data $char10.
;
campo_1 = tranwrd(campo_1,'b1'x,'c2b1'x);
campo_2 = tranwrd(campo_2,'b1'x,'c2b1'x);
Run;
在带有 SAS 和 ENCODING=UTF-8 的 Linux 系统上,我有这个文件:
more provab.txt
▒00CC00 ▒00CC00 S012016-10-04
▒00CC00 ▒00CC00 S012021-10-20
xxd provab.txt
0000000: b130 3043 4330 3020 2020 b130 3043 4330 .00CC00 .00CC0
0000010: 3020 2020 5330 3132 3031 362d 3130 2d30 0 S012016-10-0
0000020: 3420 0ab1 3030 4343 3030 2020 20b1 3030 4 ..00CC00 .00
0000030: 4343 3030 2020 2053 3031 3230 3231 2d31 CC00 S012021-1
0000040: 302d 3230 200a 0-20 .
file -i provab.txt
provab.txt: text/plain; charset=iso-8859-1
如果我在没有设置编码的情况下将其加载到 SAS 中:
Filename inp "/mypath/provab.txt" ;
Data work.current_file;
Infile inp lrecl=33 DSD MISSOVER PAD firstObs=1;
Attrib campo_1 length=
format=$char10. informat=$char10. ;
Attrib campo_2 length=
format=$char10. informat=$char10. ;
Attrib campo_3 length=
format=$char3. informat=$char3. ;
Attrib chr_data length=
format=$char10. informat=$char10. ;
Input
@1 campo_1 $char10.
@11 campo_2 $char10.
@21 campo_3 $char3.
@24 chr_data $char10.
;
Run;
我得到:
如果我设置ENCODING= LATIN1
:
Filename inp "/mypath/provab.txt"
ENCODING= LATIN1
;
Data work.current_file;
Infile inp lrecl=33 DSD MISSOVER PAD firstObs=1;
Attrib campo_1 length=
format=$char10. informat=$char10. ;
Attrib campo_2 length=
format=$char10. informat=$char10. ;
Attrib campo_3 length=
format=$char3. informat=$char3. ;
Attrib chr_data length=
format=$char10. informat=$char10. ;
Input
@1 campo_1 $char10.
@11 campo_2 $char10.
@21 campo_3 $char3.
@24 chr_data $char10.
;
Run;
我得到:
如您所见,campo_1
和 campo2
显示正确,但每个“奇怪”字符都意味着其余字段发生了变化。
例如chr_date field
,被移动了2个字符。
我用 encoding='iso-8859-1'
也得到相同的结果。
并且 iconv -f ISO-8859-1 -t UTF-8 provab.txt >provau.txt
和加载 provau.txt
我也遇到同样的异常。
我该如何解决?
根据@GiacomoCatenazzi 的评论,我猜想当您提供编码时,加载程序首先进行字符集转换,然后才将数据拆分为字段。但是由于非 ascii Latin1 字符在 UTF-8 中被转换为 2 个字节,转换打破了固定大小的字段格式。
这意味着您必须进行重要的预处理:
- 将每一行拆分为固定大小的字段
- 将每个字段转换为 UTF-8 字符集
- 用保持原始宽度的填充将字段组合回去。
这对于 Python 脚本来说是微不足道的,可能可以用 awk 来完成,但恕我直言,您不会找到这样的产品。
根据 Joop Eggen 和其他人的评论和回答,我使用 SAS 函数 tranwrd
在 加载文件后解决了我的问题。
这给出了期望的结果:
Filename inp "/mypath/provab.txt";
Data work.current_file;
Infile inp lrecl=33 DSD MISSOVER PAD firstObs=1;
Attrib campo_1 length=
format=$char10. informat=$char10. ;
Attrib campo_2 length=
format=$char10. informat=$char10. ;
Attrib campo_3 length=
format=$char3. informat=$char3. ;
Attrib chr_data length=
format=$char10. informat=$char10. ;
Input
@1 campo_1 $char10.
@11 campo_2 $char10.
@21 campo_3 $char3.
@24 chr_data $char10.
;
campo_1 = tranwrd(campo_1,'b1'x,'c2b1'x);
campo_2 = tranwrd(campo_2,'b1'x,'c2b1'x);
Run;