2011-05-16 22 views
2

我試圖讓用戶從例如阿達:如何得到整數

  1. 菜單中選擇一個模式,吃飯的時候,管理Data_error例外
  2. 飲料
  3. 睡眠

現在我可以通過調用獲得一個整數輸入

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

回答

5

幾乎所有將字符串解析爲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; 

現在,在這情況下,快速和骯髒的阿達菜單我一般不做數字菜單像上面。相反,請使用枚舉類型。這樣,您可以在菜單類型的循環中使用'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; 

關於這樣做的好處是,你不必改變你的菜單打印代碼或您的解析代碼時的菜單選項更改列表。

+0

太棒了!非常感謝!但是,我是否需要在函數的循環中另外聲明,開始和結束,還是我可以忽略聲明和開始部分? – Heartinpiece 2011-05-17 02:06:11

+0

哇!下次我在Ada中編程時,我會記住枚舉方法!謝謝! – Heartinpiece 2011-05-17 02:10:06

+0

也許我仍然陷入了過去,但在處理_console_輸入時直接調用枚舉或數字I/O包實例的Get時,我總是有點遺憾。過去的編譯器在處理「清除」交互式輸入緩衝區時,如何處理錯誤的數據輸入方面並不一致。處理這種不一致的是Get_Line/convert成語在幾年前就已經建立起來了,因爲所有的Ada編譯器似乎都至少能夠一直處理Get_Line。但最近可能會變得更好,更一致。 – 2011-05-17 12:14:47

1

您可以處理異常,要麼一個循環反覆詢問輸入中,直到輸入一個整數,或接近尾聲正常退出...

+0

哇!我不知道你可以在一個循環內實現異常!現在正常工作! – Heartinpiece 2011-05-17 02:04:46

4

中主要的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」爲退出,或「退出」;並且還可以進行任何角色預處理,如可能需要的向上套管。

+0

謝謝!讓我的程序正常運行! – Heartinpiece 2011-05-17 02:08:43

+0

應該是:Integer'Value(Response(Response'first .. Last));因爲它的實現依賴於字符串是否從0或1索引或其他... – NWS 2011-05-17 08:19:32

+0

@NWS:不,因爲Response在此示例中聲明的索引顯式範圍從1..20,Response'First是1,沒有任何實現依賴於它。雖然字符串的索引範圍可能會有所不同,但這種差異是由應用程序聲明的結果,它不依賴於任何類型的編譯器或語言依賴性。儘管當一個String變量被用作參數時,沒有提供明確的邊界信息,但通常使用String屬性('First,'Last等)來訪問它的範圍索引更好。 – 2011-05-17 12:07:44