【问题标题】:Ada: How to manage Data_error exception when getting integersAda:获取整数时如何管理 Data_error 异常
【发布时间】:2011-08-26 13:01:24
【问题描述】:

例如,我试图让用户从菜单中选择一种模式

  1. 睡觉

现在我可以通过调用获得整数输入

ada.integer_text_io.get(integer_variable);

这里的主要问题是,如果我插入一个非数字字符串(例如字符串),则会引发以下异常

raised ADA.IO_EXCEPTIONS.DATA_ERROR : a-tiinio.adb:89 instantiated at a-inteio.ads:18

我试过接收一个字符,检查它是否是一个整数,然后将它转换成一个整数,但后来我意识到我需要输入大于 1 位的整数,所以字符方法不起作用.

如果我收到一个字符串,那么我无法检查它是否为整数(除非我扫描整个字符串以查看其所有字符是否都是整数...)

除了扫描整个字符串之外,还有其他解决方案吗? 或者可能是一种异常处理技术,可能会阻止程序终止并再次要求一个正确的整数?

-CH

【问题讨论】:

    标签: exception input integer ada


    【解决方案1】:

    您可以处理异常,或者在循环内重复请求输入直到输入一个整数,或者在结束时优雅地退出......

    【讨论】:

    • 哇!我不知道你可以在循环中实现异常!!现在工作正常!
    【解决方案2】:

    用于请求此类用户输入的主要 Ada 编程习惯使用 Get_Line:

    procedure Get_Line(Item : out String;   Last : out Natural);
    

    function Get_Line return String;
    

    现在用户的响应是在字符串中,您可以快速扫描非数字字符,或使用 Integer'Value 属性将其转换为整数(将调用包装在合适的异常处理程序中)。例如:

    loop
       Put_Line("What do you want to do?");
       Display_Options;
       declare
          What_To_Do : Positive;
          Response : String(1..20);
          Last     : Natural;
       begin
          Get_Line(Response, Last);
          exit when Last = 0;
    
          What_To_Do := Integer'Value(Response(1 .. Last));  --' Buggy highlight fix
          Go_Do_Something(What_To_Do);
    
       exception
          when Data_Error =>
             Put_Line("Invalid response, try again...");
       end;
    end loop;
    

    这个成语的额外好处是您也可以接受非数字输入,例如“Q”代表 Quit,或“Quit”;还可以进行任何可能需要的字符预处理,例如向上大小写。

    【讨论】:

    • 谢谢!让我的程序正常运行!
    • 应该是:Integer'Value(Response(Response'first .. Last));因为它的实现可能取决于字符串是从 0 还是 1 或其他索引...
    • @NWS:不,因为在此示例中声明了 Response,其索引显式范围为 1 .. 20,Response'First 为 1,因此没有任何依赖于它的实现。虽然字符串的索引范围可以变化,但这种变化是应用程序声明它的结果,它依赖于任何类型的编译器或语言依赖性。虽然,当使用 String 变量作为参数时,没有提供明确的边界信息,通常最好使用 String 属性('First、'Last 等)来访问其范围索引。
    • 当你使用这个 get_Line 和声明 Response 时正确,但一般来说,在索引字符串时,不要假设任何起点。
    【解决方案3】:

    当/如果读取无效字符串时,几乎所有在 Ada 中将字符串解析为某种标量值的标准方法都会产生某种异常。这没有什么问题。只需处理异常即可。

    即使您将自己的字符串解析编写为整数例程,您也必须以某种方式处理用户输入无效字符串的情况。对吧?

    我猜唯一涉及的“技术”是您可以将异常处理程序放在子例程上,甚至放在您将内联代码放入的declare ... begin ... end 块上。这样,只有块内的代码被中止。一般来说,我更喜欢看到使用的子程序。所以你会得到类似的东西:

    function User_Integer return Integer is
    begin
        loop
            begin
                ada.integer_text_io.get(integer_variable);
                return integer_variable;
            exception
                when ADA.IO_EXCEPTIONS.DATA_ERROR =>
                    Ada.Text_IO.Put_Line ("Try a number from 1 to 3, Sherlock");
                    Print_Menu;
            end;
        end loop;
    end User_Integer;
    

    现在,既然如此,对于又快又脏的 Ada 菜单,我通常不会像上面那样做数字菜单。相反,创建一个枚举类型。这样您就可以在菜单类型的循环中使用'image 打印菜单选项,当您使用'valueAda.Text_IO.Enumeration_IO 时,Ada 将处理文本解析。

    type Menu_Selection_Option is (Eat, Drink, Sleep);
    package Menu_IO is new Ada.Text_IO.Enumeration_IO (Menu_Selection_Option);
    function User_Selection return Integer is
    begin
        loop
            declare
                Selection : Menu_Selection_Option;
            begin
                Menu_IO.Get(Selection);
                return Selection;
            exception
                when ADA.IO_EXCEPTIONS.DATA_ERROR =>
                    Ada.Text_IO.Put_Line ("Unrecognized option. Try again Sherlock");
                    Print_Menu;
            end;
        end loop;
    end User_Selection;
    

    这样做的好处是,当菜单选项列表发生变化时,您不必更改菜单打印代码或解析代码。

    【讨论】:

    • 太棒了!太感谢了!但是我是否需要在函数的循环中再声明、开始和结束,或者我可以省略声明和开始部分吗?
    • 哇!下次我在 Ada 中编程时,我会牢记枚举方法!谢谢!
    • 也许我还停留在过去,但在处理 console 时,我总是对直接调用枚举或数字 I/O 包实例化的 Get 持怀疑态度输入。过去的编译器在输入错误数据时处理“清除”交互式输入缓冲区的方式不一致。处理这种不一致是 Get_Line/convert 习语多年前建立的方式,因为所有 Ada 编译器似乎至少一致地处理 Get_Line。但也许最近情况变得更好、更一致了。
    • @Heartinpiece - 当异常处理程序运行时,它所在的块将终止。如果您将异常处理程序放在函数级别,则该函数将在处理程序代码完成后结束(并且您最好在其中有一个return 语句)。这不是你想要在这里发生的事情,因为这是一个错误条件,所以没有什么好的回报。所以,是的,可悲的是,这里需要声明块。
    • @Marc C - 实际上,通常我和你在一起。如果我从头开始编码,我会使用 Get_Line 和 Menu_Selection_Option'Value 而不是 Enumeration_IO。主要原因是你可以用它做更复杂的事情(比如打印出用户在你的异常处理程序中给你的无效输入)。然而,这更接近 OQ 试图做的事情,它应该可以工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多