Поросячья латынь переводчик - последующие


Около недели назад, я поднимал этот код и есть очень хорошая помощь. Я изменил его немного и было ищу, если кто-то рассмотрит мой второй итерации. Оригинал может быть найден здесь.

Вот новый материал. В принципе, я засунул все это в модуле, добавлена поддержка опции тире или без тире. И дал ему возможность работать с предложениями.

module PigLatin
class Translator
#how all the words end
ENDING = "ay"

def initialize (options = {:dash => true})
  @dash = options[:dash]
end

def translate (phrase)
  sentences = phrase.split(".")
  translated_sentences = sentences.map do |sentence|
    translation(sentence) + "."
  end
  translated_sentences.join(" ")
end

private

def translation (phrase)
  words = phrase.split
  translated_words = words.map do |word|
    if vowel_is_first(word)
      translate_with_vowel(word)
    else
      translate_with_consonant(word)
    end
  end
  translated_phrase = translated_words.join(" ")
  if @dash == false
    translated_phrase = translated_phrase.delete("-")
  end
  translated_phrase.capitalize
end

def vowel_is_first(word)
  return true if word[0] =~ /a|e|i|o|u|A|E|I|O|U/
  return false
end

def translate_with_vowel(word)
  "#{word}-#{"w"+ENDING}"
end

def translate_with_consonant(word)
  return "#{word[1]}-#{word[0]+ENDING}" if word.size == 2
  second_segment, first_segment = split(word)
  return "#{first_segment}-#{second_segment+ENDING}"
end

def split(word)
  split_location = word =~ /a|e|i|o|u/
  second_segment = word[0,split_location]
  first_segment = word[split_location,word.size]
  return second_segment, first_segment
end
end

class InputAcceptor

def initialize input, options
  @options = options
  @input = input
end

def do_it
  pig_latin = Translator.new(@options)
  pig_latin.translate(@input)
end

end


end
  j = PigLatin::InputAcceptor.new("Hello. You. Guy.",{:dash => false})
  p j.do_it


889
6
задан 10 мая 2011 в 07:05 Источник Поделиться
Комментарии
3 ответа

Я думаю, что это отличный способ, чтобы работать над вашими навыками, и я аплодирую вашей настойчивости здесь. В частности, важно понимать, что построение программного обеспечения, инкрементные, а в идеале существует тесная цикл развития, комментарий, рефакторинг, повторное рецензирование и т. д.

Вот некоторые комментарии от меня:

def vowel_is_first(word)
return true if word[0] =~ /a|e|i|o|u|A|E|I|O|U/
return false
end

В общем, это не стандартный стиль, чтобы использовать строки как массивы, и вы можете всегда найти другой способ, чтобы выразить то, что вам нужно, не делая этого. Кроме того, а не с помощью дизъюнкции (|) в регулярное выражение, Вы должны использовать класс персонажа - проще, понятнее, и более атомной. Мое предложение:

def vowel_is_first(word)
return word =~ /^[aeiouAEIOU]/
end

Каре (^) совпадает в начале строки (или начала строки, но мы имеем дело не с нескольких строк), а потом наш класс символов соответствует одному вхождения любого символа в квадратных скобках. Это будет возвращать ненулевое значение, если первый символ является гласной, и nil в противном случае.

Перейти к:

"#{word}-#{"w"+ENDING}"

Вам не нужно поставить строковые литералы в интерполяции, и конкатенации строк с + , как правило, следует "нет". Это было бы яснее, как:

"#{word}-w#{ENDING}"

Далее

return "#{word[1]}-#{word[0]+ENDING}" if word.size == 2

Мы должны покончить с этими массива-стиль ссылок снова. Это идеальное место для gsub:

return word.gsub(/^(.)(.)$/, "\\2-\\1#{ENDING}") if word.size == 2

Мы захватываем два одиночных символов, которые мы гарантированно из-за условной. Потом, у нас наоборот их заказ, поставив дефис между ними и заканчивая, ну, наш конец.

Что касается самой сложной части кода; в частности. translate_with_consonant для слов с более чем 2 буквы - это означает, что метод Split, который вы написали. Я согласен с sepp2k , что вы могли бы использовать встроенный в Сплит с умным регулярное выражение, чтобы разделить, но я думаю, что все это можно сделать в gsub снова. Вы должны попытаться придумать его самостоятельно.


ответным словом.gsub(/^([^aeiouAEIOU]+)([aeiouAEIOU][а-Яа-я]*)/, "\\2-\\1ay")

Странно, используя обратные кавычки и спойлер вместе делает его меньше спойлер. Да ладно.

Объяснение:


Мы смотрим на гласную в начале строки (внутри класса символов, каре означает обратное; искать то, что продается). Если мы получим более одного номера-гласный, это нормально (+ означает один или более), но мы фиксируем второй части начиная с первой гласной, и вплоть до последнего письма.

Большая вещь о этой регулярным выражением является то, что вы можете использовать его для полноты translate_with_consonant - двух букв слова вписываются. И не нужно для разделения, присоединения, объединения, либо другой метод. Кроме того, он работает лучше, если я передам тебе восклицательный знак или запятая - попробуйте!

Наконец, я бы сказал, что вам не нужен класс InputAcceptor на всех. Сохранить интерфейс простой, как sepp2k предложил, и сделать перевод происходит за один вызов метода.

Я смотрю вперед к видеть больше!

3
ответ дан 12 мая 2011 в 04:05 Источник Поделиться

Некоторые моменты в дополнение к тому, что checkorbored отметил:


  1. Вы должны использовать классы персонажей и я флаг для вашего regexen. Е. Г. вместо /А|Е|я|о|п|А|Е|я|О|У/ можно записать /[aeiou]/я.

  2. Вы должны избавиться от явного возвращения заявления, где не надо.

  3. return foo if bar
    return baz

    действительно должны быть написаны как

    if bar
    foo
    else
    baz
    end

    Если кроме фу и баз являются логическими значениями в этом случае все может быть заменено бар или !баре.


  4. def initialize (options = {:dash => true})
    @dash = options[:dash]
    end

    В данном случае это неважно, потому что есть только один вариант в ваши варианты окрошки, но обычная идиома для реализации именованных аргументов со значениями по умолчанию выглядит так:

    def initialize (options = {})
    options = {:dash => true}.merge(options)
    @dash = options[:dash]
    end

    Причина того, что (параметры = {по умолчанию}) обычно не используется, является то, что она не позволяет пользователю задать некоторые параметры, но использовать по умолчанию для других. Так что если у вас деф бла(параметры = {:ФОО => 42, бар => 23}), и пользователь звонит бла(:бар => 24) значение :фу будет ноль, а не 42. Этого не случится, если вы используете слияние вместо этого.


3
ответ дан 12 мая 2011 в 12:05 Источник Поделиться

Мои 2 цента:

Нет пробелов между именем функции и круглой скобкой: деф функция(аргумент1, аргументы)

Нет, если что-то == правда, или если что-то == ложь, прямо , если что-то или если !что-то.

Вы можете продолжать писать код после конца.

 def translate(phrase)
translated_sentences = phrase.split(".").map do |sentence|
translation(sentence) + "."
end.join(" ")
end

Не используйте переменные/обновлений, создавать новые или оставить его в другой форме:

translated_phrase = translated_words.join(" ")
if @dash == false
translated_phrase = translated_phrase.delete("-")
end

К:

translated_phrase0 = translated_words.join(" ")
translated_phrase = @dash ? translated_phrase0 : translated_phrase0.delete("-")

2
ответ дан 12 мая 2011 в 02:05 Источник Поделиться