将文本文件中的String读取到Pascal中的Array中 [英] Reading String from a text file into Array in Pascal

查看:118
本文介绍了将文本文件中的String读取到Pascal中的Array中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用此程序,我试图读取文件并将其随机打印到控制台.我想知道是否必须为此使用数组.例如,我可以将字符串分配到数组中,然后从数组中随机打印.但是,我不确定该如何处理.另一个问题是,我当前的程序无法从文件中读取第一行.我有一个文本文件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.

  1. 您的第一个Readln会将文件的第一行读入s,但是您根本不用此值.它丢失了.

  1. Your first Readln reads the first line of the file into s, but you don't use this value at all. It is lost. The first time you do a Readln in the loop, you get the second line of the file (which you do print to the console using Writeln).

您的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(textAssignReset)已过时.它不是线程安全的,可能很慢,不能很好地处理Unicode等.它在90年代使用过,但今天不应该使用.相反,请使用RTL提供的功能. (例如,在Delphi中,您可以使用TStringListIOUtils.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆