在 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_1campo2 显示正确,但每个“奇怪”字符都意味着其余字段发生了变化。

例如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;