Получаем замороженную ошибку после итерации с each_char в классе String. Какие-нибудь исправления? - PullRequest
0 голосов
/ 07 января 2020
# Character Counter
class String
  def count_char
    @lcase_count ,@upcase_count, @num_count, @spl_char_count = [0, 0 ,0 ,0]
    each_char { |char|
      if ('a'..'z').cover?(char)
        @lcase_count += 1
      elsif ('A'..'Z').cover?(char)
        @upcase_count += 1
      elsif ('0'..'9').cover?(char)
        @num_count += 1
      else
        @spl_char_count += 1
      end
      }
    return @lcase_count,@upcase_count,@num_count,@spl_char_count
  end
end

input = ARGV[0]

if ARGV.empty?
  puts 'Please provide an input'
  exit
end

puts 'Lowercase characters = %d' % [input.count_char[0]]
puts 'Uppercase characters = %d' % [input.count_char[1]]
puts 'Numeric characters = %d' % [input.count_char[2]]
puts 'Special characters = %d' % [input.count_char[3]]

Traceback (последний последний вызов): 1: от new.rb: 25: в <main>' new.rb:3:in count_char ': невозможно изменить замороженную строку (FrozenError)

Я думаю, что пока, я не изменил строку, не уверен, почему получаю FrozenError

Ответы [ 4 ]

2 голосов
/ 07 января 2020

Вы обезличиваете класс String и в то же время вводите новые переменные экземпляра в String, что уже является ужасным дизайнерским решением, потому что - если вы не являетесь автором класса String -, Вы не знаете, существуют ли эти переменные уже или нет. Затем в своем коде вы изменяете переменные, увеличивая их. Поскольку ARGV - это массив замороженных строк, вы получите ошибку.

Использование переменных экземпляра здесь абсолютно не нужно. Просто используйте обычные локальные переменные.

1 голос
/ 07 января 2020

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

class String
  def count_char
    each_char.with_object(
      {lcase_count: 0, upcase_count: 0, num_count: 0, spl_char_count: 0}
    ) do |char, acc|
      case char
      when 'a'..'z' then acc[:lcase_count] += 1
      when 'A'..'Z' then acc[:upcase_count] += 1 
      when '0'..'9' then acc[:num_count] += 1
      else acc[:spl_char_count] += 1
      end
    end
  end
end

Обратите внимание, что этот код имеет дело только с простым латинским алфавитом. Лучшим подходом будет сопоставление регулярных выражений, например:

lcase_count = scan(/\P{Lower}/).count
upcase_count = scan(/\P{Upper}/).count
...
0 голосов
/ 07 января 2020

Я не смог найти документ о том, что ARGV - замороженная строка. Но, похоже, так оно и есть. Вы можете использовать dup , чтобы исправить ошибку.

input = ARGV[0].dup
0 голосов
/ 07 января 2020

Вы можете попробовать следующее,

class String
  def count_char
    chars = { lcase_count: 0 ,upcase_count: 0, num_count: 0, spl_char_count: 0 }
    each_char do |char|
      if ('a'..'z').cover?(char)
        chars[:lcase_count] += 1
      elsif ('A'..'Z').cover?(char)
        chars[:upcase_count] += 1
      elsif ('0'..'9').cover?(char)
        chars[:num_count] += 1
      else
        chars[:spl_char_count] += 1
      end
    end
    return chars
  end
end

str = 'Asdssd'
# => "Asdssd" 
str.count_char
# => {:lcase_count=>5, :upcase_count=>1, :num_count=>0, :spl_char_count=>0} 
str.count_char[:upcase_count]
# => 1 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...