2017-09-07 5 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를 입력 "=>"이름에 공백이 ABC "를"
  3. 가 입력 "을 포함 할 수 없습니다 다시 =>

마지막 항목이 성공적으로 작동하지만,이를 확인하는 조건을 스킵 이후 나는 그것을 원하지 않는다 중복. 각각의 새로운 항목과 함께 이러한 조건을 동시에 반복하는 더 좋은 방법이 있습니까?

도움 주셔서 감사합니다.

답변

3

루프가있는 올바른 생각, 잘못된 장소. 가능한 모든 잘못된 경우에 대해 사용자의 각 gets을 확인해야합니다. 당신이 하나의 유효하지 않은 경우가 전달 될 때까지 확인하고 앞의 경우 (들)이 여전히 통과 여부를 확인하지 않은 다른 하나에 무슨 일이 있었하고 있었다 :

# 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 이후 반환 nil, check_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? 제안 된 파일 이름이 지정된 세 가지 테스트 중 하나에 대해 유효하지 않은 경우 (truthy) 메시지 문자열을 반환합니다. else nil이 리턴됩니다.
  • bad_name?이 true 값을 반환하는 경우 puts이 아닌 print을 사용하여 인쇄됩니다. 동일한 줄에 puts "Rename file '#{fn}' to:"이옵니다. 후자의 메시지는 부분적으로 사용자에게 어떤 파일의 이름이 변경되었는지 알려주는 것입니다.
  • Hash.key?은 제안 된 파일 이름이 이미 입력 된 것과 중복되는지 확인하는 데 사용됩니다. 이는 해시 키 조회가 배열 요소를 찾는 데 사용 된 선형 검색보다 훨씬 빠르기 때문입니다.
  • 새 이름에는 원래 이름이 포함될 수 있습니다. 따라서 파일의 이름을 바꾸는 데주의를 기울여야합니다. 예를 들어, "f1""f2"으로 변경하고 "f2""f1"으로 변경했다고 가정합니다. 원래 파일 이름을 새 파일 이름으로 사용하지 않으면 bad_name?에 추가 테스트를 추가해야합니다 (및 fnames을 세 번째 인수로 전달해야합니다. 방법).
  • 생성되는 해시가 마지막 단계로 반전되고 (Hash#invert 사용) 키가 원본 파일 이름이됩니다.