------=_NextPart_000_0135_01C518EF.C6101400 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit Attached is my solution. Enjoy -----Original Message----- From: Ruby Quiz [mailto:james / grayproductions.net] Sent: Friday, February 18, 2005 6:58 AM To: ruby-talk ML Subject: [QUIZ] 1-800-THE-QUIZ (#20) The three rules of Ruby Quiz: 1. Please do not post any solutions or spoiler discussion for this quiz until 48 hours have passed from the time on this message. 2. Support Ruby Quiz by submitting ideas as often as you can: http://www.rubyquiz.com/ 3. Enjoy! -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Many companies like to list their phone numbers using the letters printed on most telephones. This makes the number easier to remember for customers. A famous example being 1-800-PICK-UPS. This week's quiz is to write a program that will show a user possible matches for a list of provided phone numbers. Your script should behave as a standard Unix filter, reading from files specified as command-line arguments or STDIN when no files are given. Each line of these files will contain a single phone number. For each phone number read, your filter should output all possible word replacements from a dictionary. Your script should try to replace every digit of the provided phone number with a letter from a dictionary word; however, if no match can be made, a single digit can be left as is at that point. No two consecutive digits can remain unchanged and the program should skip over a number (producing no output) if a match cannot be made. Your script should allow the user to set a dictionary with the -d command-line option, but it's fine to use a reasonable default for your system. The dictionary is expected to have one word per line. All punctuation and whitespace should be ignored in both phone numbers and the dictionary file. The program should not be case sensative, letting "a" == "A". Output should be capital letters and digits separated at word boundaries with a single dash (-), one possible word encoding per line. For example, if your program is fed the number: 873.7829 One possible line of output is USE-RUBY According to my dictionary. The number encoding on my phone is: 2 = A B C 3 = D E F 4 = G H I 5 = J K L 6 = M N O 7 = P Q R S 8 = T U V 9 = W X Y Z Feel free to use that, or the encoding on your own phone. ------=_NextPart_000_0135_01C518EF.C6101400 Content-Type: application/octet-stream; name="phonewords.rb" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="phonewords.rb" #!/usr/bin/env ruby require 'set' require 'optparse' dict = nil ARGV.options do |opts| opts.banner = "Usage: ruby #{__FILE__} [options] [input files]" opts.on('Options:') opts.on('--dictionary DICTFILE', '-d', 'Specify dictionary file') { |file| File.open(file) { |f| dict = f.readlines } } opts.on("--help", "-h", "This text") { puts opts; exit 0 } opts.parse! end l2n = {} %w{ABC DEF GHI JKL MNO PQRS TUV WXYZ}.each_with_index { |letters, num| letters.scan(/./).each { |c| l2n[c] = "#{num + 2}" } } dict = %w{use ruby a quick brown fox jumped over the lazy laz laxx dog lazyfox f azyfox} unless dict num_dict = {} dict.each { |word| num_word = '' upword = word.upcase upword.scan(/./).each { |c| num_word << l2n[c] } (num_dict[num_word] ||= []) << upword } def build_word_list(position_list, phnumber, words = Set.new, word = '') position = word.length - word.count('-') if position >= position_list.size word.chop! while word[-1, 1] == '-' words << word return end position_list[position].each { |word_ary| next unless word_ary word_ary.each { |w| new_word = word.empty? ? "#{w}" : "#{word}-#{w}" build_word_list(position_list, phnumber, words, new_word) build_word_list(position_list, phnumber, words, "#{new_word}-#{phnumber[position + w.length, 1]}") } } words end while phone = gets next if phone.gsub!(/[^\d]/, '').empty? digits = phone.scan(/./) position_list = Array.new(digits.size) digits.each_with_index { |d, i| length_list = position_list[i] = Array.new(digits.size - i) num_word = '' (i...digits.size).each { |j| num_word << digits[j] length_list[j - i] = num_dict[num_word] } } build_word_list(position_list, phone, build_word_list(position_list, phone), phone[0,1]).each { |w| puts w } end ------=_NextPart_000_0135_01C518EF.C6101400--