【问题标题】:data file in horizontal format containing hidden characters包含隐藏字符的水平格式数据文件
【发布时间】:2014-08-12 13:28:18
【问题描述】:

我收到了一个我从未见过的格式的数据文件。数据似乎不是在列中,而是在一个长行中。我可以在Notepad 中打开文件并查看数据。因此,数据似乎没有被加密。

当我在Notepad 中打开数据文件时,当我猜测数据达到Notepad 在单行中允许的最大字符数时,数据行会回绕到Notepad 窗口的左侧,然后数据在新行中继续。

当我在Notepad 中打开文件时,可能有10,000 行数据。其中一行中的数据与其上方或下方的行中的数据不对齐。

以下是一些示例数据:

40001       1    5 GGGG  2998 HHHH SU111111       95     1.0 F1  4                1304    3        0               0
40001       1    5 GGGG  2998 HHHH SU111111       95     1.0 F1  4                0205             0     3         0
40001       1    5 GGGG  2998 HURG SU111111       95     1.0 F1  4                0805             0     2         0
40001       1    5 GGGG  2998 HHHH SU111111       95     1.0 F1  4                1205             0     2         0
40001       1    5 GGGG  2998 HHHH SU111111       95     1.0 F1  4                1505             0               0
40002       2    8 GGGG  2998 PPPP SK777777     -999     1.0 F3  4                2003             0               0
40002       2    8 GGGG  2998 PPPP SK777777     -999     1.0 F3  4                2303    2        0               0
40002       2    8 GGGG  2998 PPPP SK777777     -999     1.0 F3  4                2703    3        0               0
40002       2    8 GGGG  2998 PPPP SK777777     -999  

请注意,当我将示例数据粘贴到此处时,表示 Notepad 中的一行,这些列“神奇地”对齐。

我发现可以打开Excel中的数据文件,数据也对齐了。但是,我确实需要在Excel 中手动分配列边界。并且Excel 不允许我分配超出或多或少字符空间 123 的列边界。

下面是读取数据文件的SAS 代码,虽然这个SAS 代码不能正常工作。相反,我猜这个SAS 代码会跳过一些数据行。请注意,变量 TT 覆盖了 125-207 个字符空间,但大多数行中只有 120 个字符。某些行中有超过 120 个字符。我怀疑行之间字符数的差异是 SAS 无法正确读取此数据文件的原因。

option linesize = 210 ;
option pagesize =  30 ;

FILENAME myinput  'C:/Users/markm/simple SAS programs/mydata.new' ;

DATA mydata ;

INFILE myinput ;

INPUT

AA       2-9
BB      12-17
CC      18-22
DD   $  24-27
EE      30-33
FF   $  35-38
GG   $  40-47
HH      53-56
II      59-64
JJ   $  66-68
KK   $  70-71
LL      72-78
MM      79-85
NN   $  87-90
OO      91-95
PP     97-104
QQ    105-110
RR    112-120
SS $  122-123
TT $  125-207 ;

如果我使用右箭头键将光标在第一行数据上一次向右移动一个字符,我必须按两次右箭头键才能移动到 Notepad 中的字符空间 120 之外。

这一切都在告诉我,数据文件中存在隐藏字符,用于识别一行数据的结尾。

我打开Vim中的数据文件希望能看到这些隐藏字符,但什么也没看到。 Vim 在我打开文件时确实正确对齐了列。所以,Vim 一定会看到这些隐藏的行尾字符。

我自己如何才能看到这些行尾字符?我怀疑Vim 中有一个选项可以显示隐藏的字符。

如何确定创建此数据文件的应用程序?

如何修改上面的SAS代码才能正确读取这个数据文件?

【问题讨论】:

    标签: excel vim text sas hidden-characters


    【解决方案1】:

    首先,仔细检查您的 LRECL。你基本上丢失了一半的数据,这让我觉得你每行读两行。您将 207 显示为最大行大小,它应该低于默认的 256 LRECL,但是看到大约是正确数字的 1/2 的数字让我认为您在此处犯了一个错误。

    接下来,确定您是否看到基本上每隔一行,或者您是否看到前 44k 行然后突然停止。如果是后者,你的数据中有一个 DOS EOF 字符(1A),你需要设置IGNOREDOSEOF 选项。如果是前者,那么您可能会遇到上述明显的 LRECL 问题,或者您可能会遇到由占用多个字节的 unicode 字符引起的不明显的 LRECL 问题(尝试LRECL=32767 看看是否可以解决它;也会导致您的数据看起来每一行的某些地方都很有趣),或者你有一个奇怪的行终止符问题(尽管不一致)。

    然后,假设 EOL 字符(或 EOF?)存在问题,您处理此问题的方法是准确查看数据文件中的内容。

    读入一个虚拟字符,然后将_infile_ 行放入hex. 格式。例如:

    data test;
        infile "d:\temp\utf8.txt" lrecl=256 RECFM=f;
        input @1 x $1. @;
        r = repeat('1234567890',8); *make this appropriate for your LS option in your log;
        put r;
        put _infile_;
        put _infile_ hex512.;
        stop; *we want to see just one line here;
    run;
    

    在这种情况下,我正在阅读 20 行长行,并使用hex40.,因为它需要恰好是行长的两倍。你可以去掉长度(hex.),但如果你这样做,你会得到一些非常长的行,里面有很多空白。在你的情况下,lrecl=207,理论上你应该使用hex414.(但可能想让你的 lrecl 256hex512. 以防万一)。由于我们使用的是RECFM=F,因此我们的想法是让 LRECL 比您的实际行长更长,因此您可以在一次运行中看到一整行。 (如果一行没有告诉您足够多的信息,请使用firstobs= 导航到后面的行,认识到如果您的 LRECL 不完全适合数据,您将不会跳到真正行的开头,但跳过 256 字节块)。

    这将为您提供两个字符串,一个是“可见”字符串,这可能有助于查看 SAS 在什么位置认为是什么,一个是可见字符串后面的十六进制代码。假设您处于 ASCII 环境(不是 DBCS 或 Unicode 环境)中,十六进制代码是每个字符 2 个值(一个字节 = 2 个十六进制值)。请参阅this page 获取 ASCII 代码列表。

    要查找的十六进制代码:

    • 1A = DOS EOF 字符。
    • 0A = 低频
    • 0D = CR

    如果这是 Windows/Dos 文档,您应该在行尾连续看到 CRLF,即,0D0A 连续出现在 207 左右。如果这是 Unix 文档,您将在那里看到 0A .如果这是 Mac OS 文档,您可能会看到 LFCR 或 0A0D。为什么会有人想要保持一致。

    你可能会看到一些东西,因为你得到了一些行数。 (如果没有行终止符,SAS 只会在第一行之后放弃。)您更有可能遇到以下问题之一:

    • 这是一个 DBCS 文件,因此所有字符实际上都占用了超过一个字节。如果您在字符之间看到很多 004020(例如,每个字符都有一个),那么您就有了一个 DBCS(双字节字符集)文件 - 这就是,比如说,中文或日文版的 Windows 操作系统可能会产生。他们为 每个 字符使用两个字节,以便用他们的语言表示完整的字符集;但即使在存储英文文档时,它们仍然使用完整集 - 基本上只是添加一个填充字节,以便对于不兼容的程序(或未正确设置的程序,如本例中的 SAS)仍然具有合理的 ASCII 外观。
    • 这是一个 UTF-8 文件,其中的字符可能占用多个字节(但可能不会)。在这种情况下,当您以这种方式查看数据时,您可能会在数据中看到一些“垃圾”,并且每隔一段时间,您就会看到一个占据两个或三个空格的字符 - 通常完全充满“垃圾”字符。 UTF-8 每个字符可以占用 1 到 4 个字节,通常是 2 的幂(即 1、2、4),但对于 ASCII 字符看起来“正常”(即,它占用 ASCII 并添加了很多,在00-7F 范围)。

    我的直觉是你有一个 DBCS 文件,因为你粗略地跳过了每一行(虽然不完全是 - 而且你跳过的更多 - 这让我有点奇怪)。

    【讨论】:

    • 感谢您的回复。当我使用 INFILE myinput IGNOREDOSEOF ; SAS 时,仍然只返回 44,402 条记录。我在文档中注意到IGNOREDOSEOF 选项的结果是“任何出现的 ^Z 都被解释为字符数据”。这听起来像是以某种方式删除行尾标记可能会更好。
    • 您需要 EOL 标记,因为这就是 SAS 知道结束行的方式。你看过字符的底层十六进制代码了吗?
    • 谢谢。我将尝试查看十六进制代码。我在想如果我可以删除文件中的 $ 数据按列排列,那么 SAS 会知道每行在原始帖子中指定的字符空间范围结束的位置。虽然,也许那是不可能的。
    • 您可以使用 recfm=f 以固定长度读取行(这意味着没有 EOL 字符),但这可能比仅计算将 TERMSTR 设置为的内容更复杂(即停产)。如果您更愿意这样做,只需尝试recfm=f lrecl=207,看看它是否有效或下一行是否未对齐。如果错位 1,则设为 208。如果不是始终错位(即,并非每条线的长度都完全相同),则很难使其正常工作。
    【解决方案2】:

    查看gVim 7.4中隐藏的行尾字符的方法如下:

    1. 打开gVim 7.4

    2. 打开gVim 7.4中的数据文件

    3. 按几次escape 键以访问行编辑器。注意按退出键

    将导致gVim 7.4 窗口上没有可见结果。

    1. gVim 7.4窗口底部输入:set list

    2. enter

    完成上述操作后,我在每一行的末尾看到一个蓝色的$,我认为这是一个行尾隐藏字符。

    也许如果我能够删除这些蓝色 $ 符号并将结果保存为新名称 SAS 可能能够读取该新数据文件。如果我弄清楚了,我会发布更新。

    编辑

    我尝试修改 John Black 在此处发布的说明以删除 $,但到目前为止没有运气:Read csv file with hidden or invisible character ^M

    我输入了:%s/$//g,将蓝色的$ 替换为黄色的$。然后我以新名称保存文件并使用gVim 打开新文件。但是当我输入:set list 时,蓝色的$ 仍然存在于新文件中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-26
      • 2019-06-16
      • 2021-12-10
      • 2016-07-16
      • 2011-04-12
      • 1970-01-01
      • 2019-03-17
      相关资源
      最近更新 更多