使用 get_line() 和 put_line() 生成错误空白行的简单 ada 程序

Simple ada program producing erroneous blank lines using get_line() and put_line()

我在一个更大的程序中一直遇到这个问题,所以我制作了一个新的 ada 程序来测试它,我得到了同样的结果。

我有一个文本文件(Unix 行尾):

000_1000_0010_1001
100_0000_0010_1001
100_1000_0000_1001
100_1000_0010_0001
100_1000_0010_1001
000_0000_0011_0011
100_1000_0100
000_0000_0110
111_1111_1111
011_1111_1111
000_0000_0110

我想用它做的很简单,将每一行放在一个字符串中,然后直接打印出来。

这是我的代码:

with Ada.Text_IO; use Ada.Text_IO;
procedure Read is
   input: String(1..18);
   len: Natural;
begin
   while not End_Of_File loop
      Get_Line(input, len);
      Put_Line(input(1..len));
   end loop;

end Read;

简单吧?它用 get_line 接收每一行,将其保存到 "input" 变量,然后打印出读入的任何数量(使用从 get_line().[=16 返回的长度) =]

不幸的是,当我 运行 这段代码时,我得到了一堆空行:

gnatmake read read.adb
read < input.txt
000_1000_0010_1001

100_0000_0010_1001

100_1000_0000_1001

100_1000_0010_0001

100_1000_0010_1001

000_0000_0011_0011

100_1000_0100
000_0000_0110
111_1111_1111
011_1111_1111
000_0000_0110

我已经完成并确保我的输入文件中没有任何奇怪的行结束字符或类似的东西(我只是在 vim 中输入它们)。

这弄乱了我的程序,因为我必须考虑这些错误的空行。

知道我做错了什么吗?

你的 input 变量可以容纳 18 个字符,Get_Line 知道这一点,所以当你的输入行超过 18 个字符时,它只会读取 18 个字符。然后它将继续读取同一行,直到读取了另外 18 个字符,或者到达了行尾。在你的情况下,输入行是 exactly 18 个字符长(不包括行尾),当到达行尾时没有字符读入 input 变量 (len returns 0)...

您可以将 input 缓冲区的长度增加到比您能想到的任何输入都大,或者让运行时使用 function Get_Line return String; 计算行的长度:

with Ada.Text_IO; use Ada.Text_IO;
procedure Read is
begin
   while not End_Of_File loop
      declare
         input : String := Get_Line;
      begin
         Put_Line(input);
      end;
   end loop;
end Read;

除了egilhh回答,

首先了解背景:可能有文本行比提供的字符串长,因此行读取不完整,需要多次调用Get_Line才能读取整行。

要检测这种情况,应用程序只需检查字符串是否已填满,然后读取其余部分。为此,Get_Line 将匹配长度的情况视为不完整的行,留下 'rest' 行(0 个字符)未读。

因此,存在另一种解决方案:

   while not End_Of_File loop
      Get_Line(input, len);
      if len < input'Last then
          Put_Line(input(1..len)); -- whole (or the rest of previous) line read,
      else
          Put(input); -- (non-final) part of long line read, do not go to next
      end if;
   end loop;

   while not End_Of_File loop
      Get_Line(input, len);
      Put(input(1..len)); -- do not emit eol yet...
      if len < input'Last then
          New_Line; -- now we know: line is finished
      end if;
   end loop;