将文本文件中的String读取到Pascal中的Array中 [英] Reading String from a text file into Array in Pascal
问题描述
使用此程序,我试图读取文件并将其随机打印到控制台.我想知道是否必须为此使用数组.例如,我可以将字符串分配到数组中,然后从数组中随机打印.但是,我不确定该如何处理.另一个问题是,我当前的程序无法从文件中读取第一行.我有一个文本文件text.txt
包含
With this program, I am trying to read a file and randomly print it to console. I am wondering If I have to use arrays for that. For example, I could assign my strings into an array, and randomly print from my array. But, I'm not sure how to approach to that. Also another problem is that, my current program does not read the first line from my file. I have a text file text.txt
that contains
1. ABC
2. ABC
...
6. ABC
下面是我的代码.
type
arr = record
end;
var
x: text;
s: string;
SpacePos: word;
myArray: array of arr;
i: byte;
begin
Assign(x, 'text.txt');
reset(x);
readln(x, s);
SetLength(myArray, 0);
while not eof(x) do
begin
SetLength(myArray, Length(myArray) + 1);
readln(x, s);
WriteLn(s);
end;
end.
请让我知道如何解决这个问题!
Please let me know how I could approach this problem!
推荐答案
您的程序存在一些问题.
There are a few issues with your program.
-
您的第一个
Readln
会将文件的第一行读入s
,但是您根本不用此值.它丢失了.
Your first
Readln
reads the first line of the file intos
, but you don't use this value at all. It is lost. The first time you do aReadln
in the loop, you get the second line of the file (which you do print to the console usingWriteln
).
您的arr
记录类型在这种情况下(在大多数情况下)完全没有意义,因为它是没有任何成员的记录.它没有成员,因此无法存储任何数据.
Your arr
record type is completely meaningless in this case (and in most cases), since it is a record without any members. It cannot store any data, because it has no members.
在循环中,扩展数组的长度,一次扩展一项.但是您没有将新项目的值设置为任何值,因此您徒劳地进行了此操作. (而且,由于前一点,在任何情况下都没有设置任何值:数组的元素是空记录,不能包含任何数据.)
In your loop, you expand the length of the array, one item at a time. But you don't set the new item's value to anything, so you do this in vain. (And, because of the previous point, there isn't any value to set in any case: the elements of the array are empty records that cannot contain any data.)
一次增加一个项目的动态数组的长度是非常不好的做法,因为这可能会每次导致新的堆分配.每次都可能需要将整个现有阵列复制到计算机内存中的新位置.
Increasing the length of a dynamic array one item at a time is very bad practice, because it might cause a new heap allocation each time. The entire existing array might need to be copied to a new location in your computer's memory, every time.
循环的内容似乎正在尝试做两件事:将当前行保存在数组中,然后将其打印到控制台.我认为后者仅用于调试?
The contents of the loop seem to be trying to do two things: saving the current line in the array, and printing it to the console. I assume the latter is only for debugging?
老式Pascal I/O(text
,Assign
,Reset
)已过时.它不是线程安全的,可能很慢,不能很好地处理Unicode等.它在90年代使用过,但今天不应该使用.相反,请使用RTL提供的功能. (例如,在Delphi中,您可以使用TStringList
,IOUtils.TFile.ReadAllLines
,流等).
Old-style Pascal I/O (text
, Assign
, Reset
) is obsolete. It is not thread-safe, possibly slow, handles Unicode badly, etc. It was used in the 90s, but shouldn't be used today. Instead, use the facilities provided by your RTL. (In Delp for instance, you can use TStringList
, IOUtils.TFile.ReadAllLines
, streams, etc.)
部分固定的代码版本可能看起来像这样(仍然使用老式的Pascal I/O和效率低下的数组处理):
A partly fixed version of the code might look like this (still using old-school Pascal I/O and the inefficient array handling):
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
var
x: text;
arr: array of string;
begin
// Load file to string array (old and inefficient way)
AssignFile(x, 'D:\test.txt');
Reset(x);
try
while not Eof(x) do
begin
SetLength(arr, Length(arr) + 1);
Readln(x, arr[High(Arr)]);
end;
finally
CloseFile(x);
end;
Randomize;
// Print strings randomly
while True do
begin
Writeln(Arr[Random(Length(Arr))]);
Readln;
end;
end.
如果要解决效率低下的数组问题,但仍不使用现代类,请分块分配:
If you want to fix the inefficient array issue, but still not use modern classes, allocate in chunks:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
var
x: text;
s: string;
arr: array of string;
ActualLength: Integer;
procedure AddLineToArr(const ALine: string);
begin
if Length(arr) = ActualLength then
SetLength(arr, Round(1.5 * Length(arr)) + 1);
arr[ActualLength] := ALine;
Inc(ActualLength);
end;
begin
SetLength(arr, 1024);
ActualLength := 0; // not necessary, since a global variable is always initialized
// Load file to string array (old and inefficient way)
AssignFile(x, 'D:\test.txt');
Reset(x);
try
while not Eof(x) do
begin
Readln(x, s);
AddLineToArr(s);
end;
finally
CloseFile(x);
end;
SetLength(arr, ActualLength);
Randomize;
// Print strings randomly
while True do
begin
Writeln(Arr[Random(Length(Arr))]);
Readln;
end;
end.
但是,如果您可以使用现代班级,事情将会变得容易得多.以下示例使用现代的Delphi RTL:
But if you have access to modern classes, things get much easier. The following examples use the modern Delphi RTL:
通用TList<T>
自动处理有效的扩展:
The generic TList<T>
handles efficient expansion automatically:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Generics.Defaults, Generics.Collections;
var
x: text;
s: string;
list: TList<string>;
begin
list := TList<string>.Create;
try
// Load file to string array (old and inefficient way)
AssignFile(x, 'D:\test.txt');
Reset(x);
try
while not Eof(x) do
begin
Readln(x, s);
list.Add(s);
end;
finally
CloseFile(x);
end;
Randomize;
// Print strings randomly
while True do
begin
Writeln(list[Random(list.Count)]);
Readln;
end;
finally
list.Free;
end;
end.
但是您可以简单地使用TStringList
:
But you could simply use a TStringList
:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Classes;
var
list: TStringList;
begin
list := TStringList.Create;
try
list.LoadFromFile('D:\test.txt');
Randomize;
// Print strings randomly
while True do
begin
Writeln(list[Random(list.Count)]);
Readln;
end;
finally
list.Free;
end;
end.
或者您可以保留数组方法并使用IOUtils.TFile.ReadAllLines
:
Or you could keep the array approach and use IOUtils.TFile.ReadAllLines
:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, IOUtils;
var
arr: TArray<string>;
begin
arr := TFile.ReadAllLines('D:\test.txt');
Randomize;
// Print strings randomly
while True do
begin
Writeln(arr[Random(Length(arr))]);
Readln;
end;
end.
如您所见,现代方法更加方便(更少的代码).它们也更快,并为您提供Unicode支持.
As you can see, the modern approaches are much more convenient (less code). They are also faster and give you Unicode support.
注意:上面的所有摘录均假定文件至少包含一行.如果不是这种情况,它们将失败,在真实/生产代码中,您必须进行验证,例如像
Note: All snippets above assume that the file contains at least a single line. They will fail if this is not the case, and in real/production code, you must verify this, e.g. like
if Length(arr) = 0 then
raise Exception.Create('Array is empty.');
或
if List.Count = 0 then
raise Exception.Create('List is empty.');
在// Print strings randomly
部分之前,该部分假定数组/列表不为空.
before the // Print strings randomly
part, which assumes that the array/list isn't empty.
这篇关于将文本文件中的String读取到Pascal中的Array中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!