当前位置:  开发笔记 > 编程语言 > 正文

io的意外行为:在Erlang中的fread

如何解决《io的意外行为:在Erlang中的fread》经验,为你挑选了1个好方法。

这是一个Erlang问题.

我通过io遇到了一些意想不到的行为:fread.

我想知道是否有人可以检查我使用io的方式是否有问题:fread或者io中是否有错误:fread.

我有一个文本文件,其中包含一个"数字三角形",如下所示:

59
73 41
52 40 09
26 53 06 34
10 51 87 86 81
61 95 66 57 25 68
90 81 80 38 92 67 73
30 28 51 76 81 18 75 44
...

每对数字之间有一个空格,每一行以一个回车换行符结束.

我使用以下Erlang程序将此文件读入列表.

-module(euler67).
-author('Cayle Spandon').

-export([solve/0]).

solve() ->
    {ok, File} = file:open("triangle.txt", [read]),
    Data = read_file(File),
    ok = file:close(File),
    Data.

read_file(File) ->
    read_file(File, []).

read_file(File, Data) ->
    case io:fread(File, "", "~d") of
        {ok, [N]} -> 
            read_file(File, [N | Data]);
        eof ->
            lists:reverse(Data)
    end.

该程序的输出是:

(erlide@cayle-spandons-computer.local)30> euler67:solve().
[59,73,41,52,40,9,26,53,6,3410,51,87,86,8161,95,66,57,25,
 6890,81,80,38,92,67,7330,28,51,76,81|...]

注意如何将第四行(34)的最后一个数字和第五行(10)的第一个数字合并为单个数字3410.

当我使用"od"转储文本文件时,这些行没有什么特别之处; 他们就像任何其他行一样以cr-nl结尾:

> od -t a triangle.txt
0000000    5   9  cr  nl   7   3  sp   4   1  cr  nl   5   2  sp   4   0
0000020   sp   0   9  cr  nl   2   6  sp   5   3  sp   0   6  sp   3   4
0000040   cr  nl   1   0  sp   5   1  sp   8   7  sp   8   6  sp   8   1
0000060   cr  nl   6   1  sp   9   5  sp   6   6  sp   5   7  sp   2   5
0000100   sp   6   8  cr  nl   9   0  sp   8   1  sp   8   0  sp   3   8
0000120   sp   9   2  sp   6   7  sp   7   3  cr  nl   3   0  sp   2   8
0000140   sp   5   1  sp   7   6  sp   8   1  sp   1   8  sp   7   5  sp
0000160    4   4  cr  nl   8   4  sp   1   4  sp   9   5  sp   8   7  sp

一个有趣的观察是,问题发生的一些数字恰好在文本文件中的16字节边界上(但不是全部,例如6890).



1> womble..:

我将继续将它作为Erlang中的一个错误,并且是一个奇怪的错误.将格式字符串更改为"~2s"会产生同样奇怪的结果:

["59","73","4","15","2","40","0","92","6","53","0","6","34",
 "10","5","1","87","8","6","81","61","9","5","66","5","7",
 "25","6",
 [...]|...]

因此,为了计数,它似乎将换行符计为常规字符,但在生成输出时则不然.懒散如此.

一周的Erlang编程,我已经深入研究了源代码.那可能是我的新纪录......

编辑

更多的调查证实,这是一个错误.调用以下内部方法之一fread:

> io_lib_fread:fread([], "12 13\n14 15 16\n17 18 19 20\n", "~d").           
{done,{ok,"\f"}," 1314 15 16\n17 18 19 20\n"}

基本上,如果要读取多个值,那么换行,第一个换行符将在字符串的"仍待读取"部分中被吃掉.其他测试表明,如果你预先添加一个空格就可以了,如果你用一个换行符引导字符串,它会要求更多.

我要深究这一点,gosh-darn-it ...(笑)没有那么多代码可以通过,而且没有太多的代码专门用于换行,所以它不应该花太长时间缩小范围并修复它.

编辑^ 2

哈哈!得到了一点点.

这是你想要的stdlib的补丁(记得重新编译并将新的beam文件放在旧的顶部):

--- ../erlang/erlang-12.b.3-dfsg/lib/stdlib/src/io_lib_fread.erl
+++ ./io_lib_fread.erl
@@ -35,9 +35,9 @@
     fread_collect(MoreChars, [], Rest, RestFormat, N, Inputs).

 fread_collect([$\r|More], Stack, Rest, RestFormat, N, Inputs) ->
-    fread(RestFormat, Rest ++ reverse(Stack), N, Inputs, More);
+    fread(RestFormat, Rest ++ reverse(Stack), N, Inputs, [$\r|More]);
 fread_collect([$\n|More], Stack, Rest, RestFormat, N, Inputs) ->
-    fread(RestFormat, Rest ++ reverse(Stack), N, Inputs, More);
+    fread(RestFormat, Rest ++ reverse(Stack), N, Inputs, [$\n|More]);
 fread_collect([C|More], Stack, Rest, RestFormat, N, Inputs) ->
     fread_collect(More, [C|Stack], Rest, RestFormat, N, Inputs);
 fread_collect([], Stack, Rest, RestFormat, N, Inputs) ->
@@ -55,8 +55,8 @@
                eof ->
                    fread(RestFormat,eof,N,Inputs,eof);
                _ ->
-                   %% Don't forget to count the newline.
-                   {more,{More,RestFormat,N+1,Inputs}}
+                   %% Don't forget to strip and count the newline.
+                   {more,{tl(More),RestFormat,N+1,Inputs}}
            end;
        Other ->                                %An error has occurred
            {done,Other,More}

现在提交我的补丁到erlang-patches,并获得由此产生的名声和荣耀......

推荐阅读
云聪京初瑞子_617
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有