2017-09-07 124 views
1

我使用Ruby從用戶獲取輸入以爲文件列表提供新名稱。我將這些名稱存儲在一個數組中,但在存儲它之前,我有一系列條件循環來確保用戶的輸入有效。它本質歸結爲這(我已刪除了不相關的問題的部分代碼):循環多個條件,直到滿足所有條件

puts "Rename file to:" 
new_name = gets.chomp 
new_name = check_input(new_name,@all_names) 
@all_names << new_name 

def check_input(new_name,all_names) 

    while new_name.match(/\s/) 
     puts "Names must not contain spaces:" 
     new_name = gets.chomp 
    end 

    while new_name.empty? 
     puts "Please enter a name:" 
     new_name = gets.chomp 
    end 

    while all_names.include? new_name 
     puts "That name already exists. Please enter a different name:" 
     new_name = gets.chomp 
    end 

    return new_name 

end 

總體而言,這工作得很好,但我想通過每一個「,同時確保循環「情況一次又一次,直到全部的條件得到滿足。如果,例如,一個名爲「ABC」已經存在,用戶按照這個順序:

  1. 進入「ABC」 =>「這個名字已經存在,請輸入一個不同的 名」
  2. 進入「ABC 「=>‘的名稱不能包含空格’
  3. 進入‘ABC’再次=>

中的最後一項工作的成功,但我不希望它,因爲它跳過來檢查的條件重複。是否有更好的方法同時循環這些條件,每個新條目?

謝謝你的幫助!

回答

3

正確的想法與循環,只是錯誤的地方。您需要檢查來自用戶的每個gets,以防所有可能的無效情況。你這樣做是檢查,直到一個無效的情況下獲得通過,然後去到不同的地方,如果前面的情況下(S)還通過了其中未檢查:

# outputs an error message and returns nil if the input is not valid. 
# Otherwise returns the input 
def check_input(input, all_names) 
    if input.match(/\s/) 
    puts "Name must not contain spaces:" 
    elsif input.empty? 
    puts "Please enter a name:" 
    elsif all_names.include?(input) 
    puts "That name already exists. Please enter a different name:" 
    else 
    input 
    end 
end 

@all_names = ['abc'] 
puts "Rename file to:" 
# keep gets-ing input from the user until the input is valid 
name = check_input(gets.chomp, @all_names) until name 
@all_names << name 
puts @all_names.inspect 

由於puts回報nilcheck_input如果輸入無效,將返回nil。否則,在最後的else中,我們將返回有效輸入並將其分配給變量name並停止執行until循環。

運行示例:

重命名文件:
ABC
這名已經存在。請輸入一個不同的名稱:
A B C
名稱不能包含空格:
ABC
這名已經存在。請輸入一個不同的名稱:
abc23
[ 「ABC」, 「abc23」]

+0

精美高效。非常感謝! – lumos

0

這可能是遞歸很好的利用(只顯示這裏的條件之一,其他的結構相同):

def check_input(new_name,all_names) 

    # using if instead of while ... recursion provides the 'loop' here 
    if new_name.match(/\s/) 
     puts "Names must not contain spaces:" 
     new_name = check_input(gets.chomp, all_names) 
    end 

    # etc, other conditionals 

    new_name 

end 

從本質上講,所有這些new_name分配將解決,直到輸入通過所有檢查。程序進入堆棧更深入,但一旦某些輸入通過所有檢查,一切都會解決。

0

是的,遞歸是正確的方式來做這樣的事情,我認爲。只是在一個test.rb文件拋出此並運行ruby test.rb

@all_names = [] 

def check_name(name = nil) 
    # Find out if it's invalid and why 
    invalid_reason = if name.empty? 
     "Please enter a name:" 
    elsif name.match(/\s/) 
     "Names must not contain spaces:" 
    elsif @all_names.include?(name) 
     "That name already exists. Please enter a different name:" 
    end 

    # Either return the name or ask for it again 
    if invalid_reason 
     puts invalid_reason 
     name = check_name(gets.chomp) 
    end 

    # Once we have it return the name! 
    name 
end 

puts "Rename file to:" 
new_name = check_name(gets.chomp) 
puts "Successfully storing name '#{new_name}'..." 
@all_names << new_name 

讓我知道這是做什麼你要找的人!

1

代碼

def rename_files(fnames) 
    fnames.each_with_object({}) do |fn,h| 
    loop do 
     puts "Rename file '#{fn}' to:" 
     new_name = gets.chomp 
     bad_name = bad_name?(new_name, h) 
     if bad_name 
     print bad_name 
     else 
     h.update(new_name=>fn) 
     break 
     end 
    end 
    end.invert 
end 

def bad_name?(new_name, h) 
    if new_name.include?(' ') 
    "Names must not contain spaces. " 
    elsif new_name.empty? 
    "Names cannot be empty. " 
    elsif h.key?(new_name) 
    "That name already exists. Duplicates are not permitted. " 
    else 
    nil 
    end 
end 

rename_files(["cat", "dog", "pig"]) 
Rename file 'cat' to: 
    # <enter "three blind mice"> 
Names must not contain spaces. Rename file 'cat' to: 
    # <enter ENTER only> 
Names cannot be empty. Rename file 'cat' to: 
    # <enter "three_blind_mice"> 
Rename file 'dog' to: 
    # <enter "four_blind_mice"> 
Rename file 'pig' to: 
    # <enter "three_blind_mice?> 
That name already exists. Duplicates are not permitted. Rename file 'pig' to: 
    # <enter "five_blind_mice" 
    #=> {"cat"=>"three_blind_mice", "dog"=>"four_blind_mice", "pig"=>"five_blind_mice"} 

注意

  • bad_name?如果建議的文件名對於三個指定測試之一是無效的,則返回一個(真值)消息字符串;否則返回nil
  • 如果bad_name?返回真值,則使用print而不是puts打印,因爲它將在同一行上跟隨puts "Rename file '#{fn}' to:"。後面的消息部分是爲了提醒用戶正在重命名哪個文件。
  • Hash.key?用於確定建議的文件名是否與已經輸入的文件名重複,部分原因是因爲散列鍵查找比用於查找數組元素的線性搜索快得多。
  • 新名稱可能包含原始名稱。因此必須注意重命名文件。 (例如,考慮將"f1"更改爲"f2",並將"f2"更改爲"f1"。)如果沒有原始名稱將用作新文件名,則必須將其他測試添加到bad_name?(並且必須將fnames作爲第三個參數傳遞給該名稱方法)。
  • 作爲最後一步,正在構造的散列被反轉(使用Hash#invert),以便鍵是原始文件名。