此代码有问题,我有两个文件char,一个文件中包含有关图书的信息,另一个是空的,我必须在SAL中写一些S的信息,然后显示总共多少本书匹配代码的前两位数字以及R和T的数量。该代码确实将信息表S写入了Sal,但是当它应该显示总计时,在屏幕上显示ERORR 100。我读到它,并说这是“磁盘读取错误”的问题,并且*如果您“播种”不存在键入文件的记录并尝试对其进行读取/写入,通常会发生此错误。 *,我真的不懂。
我一直想弄清楚,但我一直没能。我注意到,如果我不输入“ WHILE NOT EOF(S)DO”,则不会出现该错误,但是我当然需要一段时间,如果有人能够指出我的错误,我将非常感激。
这是代码:
uses crt;
var
i : byte;
s,sal: file of char;
v,l1,l2: char;
cs,cn,cl: integer;
pn,ps,tot: integer;
BEGIN
cs:=0; cn:=0; i:=0; cl:=0;
Assign (s, 'C:\Users\te\Documents\s.txt');
{$I-}
Reset (s);
{$I+}
if IOResult <> 0 then
begin
writeln('Error');
halt(2);
end;
Assign (sal, 'C:\Users\te\Documents\sal.txt');
{$I-}
Rewrite (sal);
IOResult;
{$I+}
if IOResult <> 0 then
halt(2);
writeln('Please write the code of the book, only 2 digits');
read(L1);read(L2);
read(s,v);
while (not eof(s)) do
begin
for i:=1 to 2 do
read(s,v);
if (v = '0') then
begin
read(s,v);
if (v = '1') or (v = '2') then
begin
for i:=1 to 5 do
read(s,v);
if (v = 'R') then
begin
read(s,v);
cs:= cs + 1;
end
else
begin
if (v = 'T') then
begin
cn:= cn + 1;
read(s,v);
end;
end;
while (v <> '-') do
read(s,v);
while (v = '-') do
read(s,v);
if (v = L1) then
begin
write(sal, v);
read(s,v);
if (v = L2) then
begin
write(sal,v);
read(s,v);
cl:= cl + 1;
end;
end;
while ( v <> '/') do
begin
write(sal,v);
read(s,v);
end;
write(sal, '-');
end
else
begin
for i:= 1 to 5 do
read(s,v);
if (v = 'R') then
cs:= cs + 1
else
cn:= cn + 1;
if (v = L1) then
read(s,v);
if (v = L2) then
begin
cl:= cl + 1;
read(s,v);
end;
end;
end
else
begin
for i:= 1 to 5 do
read(s,v);
if (v = 'R') then
cs:= cs + 1
else
cn:= cn + 1;
if (v = L1) then
read(s,v);
if (v = L2) then
begin
cl:= cl + 1;
read(s,v);
end;
end;
end;
tot:= cs + cn;
ps:= (cs * 100) div tot;
pn:= (cn * 100) div tot;
writeln('TOTAL ',cl);
writeln();
writeln(ps,'% and',pn,'%');
文件S的内容:
02022013Rto kill a mockingbird-1301/02012014Tpeter pan-1001/02032013Thowto-2301/02012012Tmaze runner-1001/02012012Tmaze runner-1001/02012012Tmaze runner-1001/$
我真的只需要别人对这段代码的看法,我认为算法可能有缺陷。 谢谢
答案 0 :(得分:2)
(编辑后,我看到您的代码现在可以在FPC中编译没有错误的代码,因此很高兴您能够自己解决错误)
因为这显然是课程,所以我不会为您修复代码,无论如何也不会为您修改即使如此,我担心您这样做还是完全错误的。
基本上,代码的主要错误是您试图控制逐个字符读取源文件时发生的情况。坦率地说,这是尝试执行此操作的绝望方式,因为它使执行流程不必要地变得复杂,并且被ifs,buts和loop所困扰。它还要求您始终牢记在任何给定步骤中尝试执行的操作,并且所生成的代码本质上是不自我记录的文件-假设您是否会在六个月后回到自己的代码中,您能一眼看出它是如何工作的吗?我非常不能亲自。
您需要以其他方式分解任务。而不是从下至上分析问题(“如果我接下来阅读此字符,那么我下一步需要做的是...”)从上至下进行分析:尽管您的输入文件是file of char
,它包含一系列由/
字符分隔并最终由$
终止的字符串(但此终止符并不重要),因此您需要做的是逐个读取这些字符串-一个;一旦找到一个,就检查它是否在寻找:如果是,请按需要进行处理,否则请阅读下一个,直到到达文件末尾。
一旦您成功阅读了其中一本书的书串,就可以将其拆分成组成书本的各个字段。进行拆分的最有用的功能可能是Copy
,它使您可以从字符串中提取子字符串-在FPC帮助中查找它。我提供了函数ExtractTitle
和ExtractPreamble
,向您展示了编写类似的函数以提取T / R代码和连字符后的数字代码所需执行的操作。顺便说一句,如果您以后需要询问类似的q,那么如果在文件中包含布局说明和各个字段的含义,将非常有帮助。
因此,我要向您展示的是如何通过逐个字符地构建S.Txt
中的字符串系列。在下面的代码中,我使用函数GetNextBook
进行此操作,我希望这是不言而喻的。代码在while
循环中使用此函数来填充BookRecord
字符串变量。然后,它仅将BookRecord
写入控制台。当然,您的代码应该做的是处理BookRecord
的内容以查看它是否是您要寻找的内容,然后确定任务的其余部分是否存在。
我希望您同意以下代码比q中的代码更清晰,更短并且将来更易于扩展。他们以这种方式构造程序的关键是将程序的任务分解为一系列功能和过程,每个功能和过程都执行一个子任务。以这种方式编写程序,可以更轻松地“重新连接”程序以更改其功能,而不必重写函数/过程的内部。
program fileofcharproject;
uses crt;
const
sContents = '02022013Rto kill a mockingbird-1301/02012014Tpeter pan-1001/02032013Thowto-2301/02012012Tmaze runner-1001/02012012Tmaze runner-1001/02012012Tmaze runner-1001/$';
InputFileName = 'C:\Users\MA\Documents\S.Txt';
OutputFileName = 'C:\Users\MA\Documents\Sal.Txt';
type
CharFile = File of Char; // this is to permit a file of char to be used
// as a parameter to a function/procedure
function GetNextBook(var S : CharFile) : String;
var
InputChar : Char;
begin
Result := '';
InputChar := Chr(0);
while not Eof(S) do begin
Read(S, InputChar);
// next, check that the char we've read is not a '/'
// if it is a '/' then exit this while loop
if (InputChar <> '/') then
Result := Result + InputChar
else
Break;
end;
end;
function ExtractBookTitle(BookRecord : String) : String;
var
p : Integer;
begin
Result := Copy(BookRecord, 10, Length(BookRecord));
p := Pos('-', Result);
if p > 0 then
Result := Copy(Result, 1, p - 1);
end;
procedure AddToOutputFile(var OutputFile : CharFile; BookRecord : String);
var
i : Integer;
begin
for i := 1 to Length(BookRecord) do
write(OutputFile, BookRecord[i]);
write(OutputFile, '/');
end;
function ExtractPreamble(BookRecord : String) : String;
begin
Result := Copy(BookRecord, 1, 8);
end;
function TitleMatches(PartialTitle, BookRecord : String) : Boolean;
begin
Result := Pos(PartialTitle, ExtractBookTitle(BookRecord)) > 0;
end;
var
i : Integer; //byte;
s,sal: file of char;
l1,l2: char;
InputChar : Char;
BookFound : Boolean;
cs,cn,cl: integer;
pn,ps,tot: integer;
Contents : String;
BookRecord : String;
PartialTitle : String;
begin
// First, create S.Txt so we don't have to make any assumptions about
// its contents
Contents := sContents;
Assign(s, InputFileName);
Rewrite(s);
for i := 1 to Length(Contents) do begin
write(s, Contents[i]); // writes the i'th character of Contents to the file
end;
Close(s);
cs:=0; cn:=0; i:=0; cl:=0;
// Open the input file
Assign (s, InputFileName);
{$I-}
Reset (s);
{$I+}
if IOResult <> 0 then
begin
writeln('Error');
halt(2);
end;
// Open the output file
Assign (sal, OutputFileName);
{$I-}
Rewrite (sal);
IOResult;
{$I+}
if IOResult <> 0 then
halt(2);
// the following reads the BookRecords one-by-one and copies
// any of them which match the partial title to sal.txt
writeln('Enter part of a book title, followed by [Enter]');
readln(PartialTitle);
while not Eof(s) do begin
BookRecord := GetNextBook(S);
writeln(BookRecord);
writeln('Preamble : ', ExtractPreamble(BookRecord));
writeln('Title : ', ExtractBookTitle(BookRecord));
if TitleMatches(PartialTitle, BookRecord) then
AddToOutputFile(sal, BookRecord);
end;
// add file '$' to sal.txt
write(sal, '$');
Close(sal);
Close(s);
writeln('Done, press any key');
readln;
end.