这是一个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).
我将继续将它作为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,并获得由此产生的名声和荣耀......