2009-01-23 11 views
6

में फ़्रेड यह एक एरलांग प्रश्न है।आईओ का अप्रत्याशित व्यवहार: एरलांग

मैंने 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. 

इस कार्यक्रम का उत्पादन होता है:

 
([email protected])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-बाइट सीमा पर होने के लिए होने से कुछ, उदाहरण के लिए 68 9 0)।

+0

यह सब कुछ एक बग की तरह दिखता है। डेटा की लंबाई लेते हुए पता चलता है कि यह 32 तत्व हैं, 36 तत्व नहीं। अन्य प्रारूपों में डेटा व्यवस्थित करना सिर्फ गड़बड़ को चारों तरफ ले जाता है। (मैंने इसे Vista + Erland 5.6.5 में आजमाया)। – Godeke

उत्तर

9

मैं इसके साथ एरलांग में भी एक बग होने जा रहा हूं, और एक अजीब व्यक्ति हूं। प्रारूप स्ट्रिंग बदलने के लिए "~ 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", 
[...]|...] 

तो ऐसा लगता है कि यह उनकी गिनती के प्रयोजनों के लिए एक नियमित रूप से चरित्र के रूप में एक नई पंक्ति चरित्र गिनती है, लेकिन नहीं, जब यह उत्पादन के उत्पादन के लिए आता है। लूपी सभी नरक के रूप में।

एरलांग प्रोग्रामिंग का एक सप्ताह, और मैं पहले ही स्रोत में जा रहा हूं। वह मेरे लिए एक नया रिकार्ड ...

संपादित

एक थोड़ा और अधिक जांच मेरे लिए पुष्टि की है कि यह एक बग है हो सकता है। आंतरिक तरीकों है कि 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"} 

मूल रूप से, अगर वहाँ एक से अधिक मान पढ़ने के लिए है, तो एक नई पंक्ति, पहले न्यू लाइन "अभी भी पढ़ने के लिए" स्ट्रिंग के भाग में खाया जाता है। अन्य परीक्षण से पता चलता है कि यदि आप एक स्थान तैयार करते हैं तो यह ठीक है, और यदि आप एक नई लाइन के साथ स्ट्रिंग का नेतृत्व करते हैं तो यह और पूछता है।

मैं इसके नीचे पहुंचने जा रहा हूं, गोश-डर्न-इट ... (ग्रिन) इसमें इतना कोड नहीं है, और इसमें से अधिकतर विशेष रूप से न्यूलाइन के साथ सौदा नहीं करते हैं, इसलिए इसे ' इसे कम करने और इसे ठीक करने में बहुत लंबा समय लगता है।

संपादित करें^2

हा हा! थोड़ा हल्का मिला।

यहाँ है कि आप चाहते हैं (पुन: संयोजित और पुराने एक के शीर्ष पर नई किरण फ़ाइल ड्रॉप करना ना भूलें) stdlib को पैच है:

--- ../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-पैच करने के लिए अपने पैच प्रस्तुत करने के लिए, और परिणामस्वरूप प्रसिद्धि और महिमा काट लें ...

+0

ऐसा लगता है कि आप गर्म हो रहे हैं। इस के निचले हिस्से तक पहुंचने के लिए समय निकालने के लिए धन्यवाद। –

0

मैंने देखा कि कई उदाहरण हैं जहां दो संख्याएं विलय हो गई हैं, और यह चौथी रेखा से आगे की प्रत्येक पंक्ति पर रेखा सीमाओं पर दिखाई देती है।

मैंने पाया कि अगर आप पांचवें से शुरू हर पंक्ति के आरम्भ में एक खाली स्थान के चरित्र जोड़ने के लिए, वह यह है कि:

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 
... 

संख्या ठीक प्रकार से पार्स हो:

39> euler67:solve(). 
[59,73,41,52,40,9,26,53,6,34,10,51,87,86,81,61,95,66,57,25, 
68,90,81,80,38,92,67,73,30|...] 

यह भी काम करता है यदि आप पहले चार लाइनों की शुरुआत में व्हाइटस्पेस भी जोड़ते हैं।

यह वास्तविक समाधान से अधिक कामकाज है, लेकिन यह काम करता है। मैं यह जानना चाहता हूं कि आईओओ के लिए प्रारूप स्ट्रिंग कैसे सेट अप करें: इस तरह से फ़्रेड करें कि हमें ऐसा नहीं करना पड़ेगा।

अद्यतन यहाँ एक समाधान है कि आप फ़ाइल को बदलने के लिए मजबूर नहीं होगा। मतलब यह है कि सभी अंक दो अक्षर (< 100) हैं:

read_file(File, Data) -> 
case io:fread(File, "", "~d") of 
    {ok, [N] } -> 
     if 
      N > 100 -> 
       First = N div 100, 
       Second = N - (First * 100), 
       read_file(File, [First , Second | Data]); 

      true -> 
       read_file(File, [N | Data]) 
     end; 
    eof -> 
     lists:reverse(Data) 
end. 

असल में, कोड संख्या जो एक नई पंक्ति भर में दो के संयोजन कर रहे हैं और उन्हें दो में विभाजित के किसी भी फैल जाती है।

फिर, यह एक कड़वाहट है जो io: fread में संभावित बग का तात्पर्य है, लेकिन इसे करना चाहिए।

अपडेट फिर से ऊपर केवल दो अंकों आदानों के लिए काम करेंगे, लेकिन उदाहरण के बाद से सभी अंक पैक (यहां तक ​​कि उन < 10) एक दो अंकों प्रारूप, कि इस उदाहरण के लिए काम करेंगे में।

+0

धन्यवाद! यह सहायता करता है।यदि आपको एक प्रारूप स्ट्रिंग मिलती है जो काम करता है, तो यह भी सहायक होगा। लेकिन यह सुनिश्चित करने के लिए कि हम एक ही पृष्ठ पर हैं: क्या आपको लगता है कि प्रारूप स्ट्रिंग जो मैं अब उपयोग कर रहा हूं (अर्थात् "~ d") को मेरी मूल फ़ाइल के साथ काम करना चाहिए? दूसरे शब्दों में: आईओ में एक बग है: फ्रेड? –

+0

मुझे कोई कारण नहीं दिखता कि इसे मूल फ़ाइल के साथ क्यों काम नहीं करना चाहिए, लेकिन मैं अभी भी एरलांग के लिए कुछ नया हूं, इसलिए मुझे कुछ याद आ रहा है। यह निश्चित रूप से एक बग हो सकता है, लेकिन मुझे इस बिंदु पर यकीन नहीं है। – Vector

+0

आपका वर्कअराउंड यह भी मानता है कि सभी नंबर बिल्कुल दो अंक हैं - यह 1 \ n2 के लिए काम नहीं करेगा, क्योंकि यह 12 के रूप में आएगा, और विभाजित नहीं किया जाएगा। – womble

1

इस तथ्य के अलावा कि यह एरलंग libs में से एक में एक बग प्रतीत होता है, मुझे लगता है कि आप आसानी से समस्या को बाधित कर सकते हैं।

तथ्य यह है कि आपकी फ़ाइल लाइन उन्मुख है, मुझे लगता है कि सबसे अच्छा अभ्यास यह है कि आप इसे लाइन-लाइन-लाइन भी संसाधित करते हैं।

निम्नलिखित निर्माण पर विचार करें। यह एक unpatched erlang पर अच्छी तरह से काम करता है और क्योंकि यह आलसी मूल्यांकन का उपयोग करता है, यह सब यादृच्छिक लंबाई की फ़ाइलों को पहले स्मृति में पढ़ने के बिना संभाल सकता है। मॉड्यूल में प्रत्येक पंक्ति पर लागू करने के लिए फ़ंक्शन का एक उदाहरण होता है - पूर्णांक की सूची में पूर्णांक के टेक्स्ट-प्रस्तुतियों की एक पंक्ति को बदलना।


-module(liner). 
-author("Harro Verkouter"). 
-export([liner/2, integerize/0, lazyfile/1]). 

% Applies a function to all lines of the file 
% before reducing (foldl). 
liner(File, Fun) -> 
    lists:foldl(fun(X, Acc) -> Acc++Fun(X) end, [], lazyfile(File)). 

% Reads the lines of a file in a lazy fashion 
lazyfile(File) -> 
    {ok, Fd} = file:open(File, [read]), 
    lazylines(Fd). 
% Actually, this one does the lazy read ;) 
lazylines(Fd) -> 
    case io:get_line(Fd, "") of 
     eof -> file:close(Fd), []; 
     {error, Reason} -> 
      file:close(Fd), exit(Reason); 
     L -> 
      [L|lazylines(Fd)] 
    end. 

% Take a line of space separated integers (string) and transform 
% them into a list of integers 
integerize() -> 
    fun(X) -> 
     lists:map(fun(Y) -> list_to_integer(Y) end, 
       string:tokens(X, " \n")) end. 


Example usage: 
Eshell V5.6.5 (abort with ^G) 
1> c(liner). 
{ok,liner} 
2> liner:liner("triangle.txt", liner:integerize()). 
[59,73,41,52,40,9,26,53,6,34,10,51,87,86,81,61,95,66,57,25, 
68,90,81,80,38,92,67,73,30|...] 

And as a bonus, you can easily fold over the lines of any (lineoriented) file w/o running out of memory :) 

6> lists:foldl(fun(X, Acc) -> 
6>     io:format("~.2w: ~s", [Acc,X]), Acc+1 
6>     end, 
6>    1, 
6>    liner:lazyfile("triangle.txt")).           
1: 59 
2: 73 41 
3: 52 40 09 
4: 26 53 06 34 
5: 10 51 87 86 81 
6: 61 95 66 57 25 68 
7: 90 81 80 38 92 67 73 
8: 30 28 51 76 81 18 75 44 

चीयर्स, एच।

संबंधित मुद्दे